-- Copyright 2014 Evan Laforge
-- This program is distributed under the terms of the GNU General Public
-- License 3.0, see COPYING or http://www.gnu.org/licenses/gpl-3.0.txt

{- | Saih pitu scales.

    @
    3i 3o 3e 3u 3a 4i 4o 4e 4u 4a 5i 5o 5e 5u 5a 6i 6o 6e 6u 6a 7i
    jegog---------
                   calung--------
                                  penyacah------
       ugal-------------------------
          rambat-----------------------------------
    0              7              14             21             28
    3i 3o 3e 3u 3a 4i 4o 4e 4u 4a 5i 5o 5e 5u 5a 6i 6o 6e 6u 6a 7i
                trompong---------------------
                      pemade-----------------------
                                     kantilan---------------------
                         reyong-----------------------------
                         |1-----|---       |3--|---
                                  |2-----|---    |4--------|
    3i 3o 3e 3u 3a 4i 4o 4e 4u 4a 5i 5o 5e 5u 5a 6i 6o 6e 6u 6a 7i
    @
-}
module Derive.Scale.Legong where
import qualified Data.Map as Map
import qualified Data.Vector as Vector

import qualified Util.Doc as Doc
import qualified Util.Lists as Lists
import qualified Util.Texts as Texts

import qualified Derive.Scale as Scale
import qualified Derive.Scale.Bali as Bali
import qualified Derive.Scale.BaliScales as BaliScales
import qualified Derive.Scale.ChromaticScales as ChromaticScales
import qualified Derive.Scale.McPhee as McPhee
import qualified Derive.Scale.Scales as Scales
import qualified Derive.Scale.Theory as Theory
import qualified Derive.ShowVal as ShowVal

import qualified Midi.Key as Key
import qualified Midi.Midi as Midi
import qualified Perform.Midi.Patch as Patch
import qualified Perform.Pitch as Pitch

import Global


scales :: [Scale.Definition]
scales :: [Definition]
scales = Config -> ScaleId -> Doc -> [Definition]
make_scale_set Config
config ScaleId
scale_id Doc
"Saih pelegongan, from my instruments."

scale_id :: Pitch.ScaleId
scale_id :: ScaleId
scale_id = ScaleId
"legong"

make_scale_set :: BaliScales.Config -> Pitch.ScaleId -> Doc.Doc
    -> [Scale.Definition]
make_scale_set :: Config -> ScaleId -> Doc -> [Definition]
make_scale_set Config
config (Pitch.ScaleId Text
prefix) Doc
doc =
    forall a b. (a -> b) -> [a] -> [b]
map (Scale -> Definition
Scale.Simple forall b c a. (b -> c) -> (a -> b) -> a -> c
. Doc -> Scale -> Scale
Scales.add_doc Doc
doc)
    [ ScaleId -> ScaleMap -> Scale
BaliScales.make_scale (Text -> ScaleId
id_with Text
"") (Format -> ScaleMap
scale_map Format
complete_scale)
    , ScaleId -> ScaleMap -> Scale
BaliScales.make_scale (Text -> ScaleId
id_with Text
"b") (Format -> ScaleMap
scale_map Format
complete_scale_balinese)
    , Doc -> Scale -> Scale
Scales.add_doc Doc
"Use Javanese-style cipher notation." forall a b. (a -> b) -> a -> b
$
        -- TODO use 4 and 7 instead of 3# and 6#.
        -- Use simple_scale like *wayang and *selesir?
        ScaleId -> ScaleMap -> Scale
BaliScales.make_scale (Text -> ScaleId
id_with Text
"c") (Format -> ScaleMap
scale_map Format
cipher_scale)
    , Doc -> Scale -> Scale
inst_doc Doc
"pemade" forall a b. (a -> b) -> a -> b
$ ScaleId -> ScaleMap -> Scale
BaliScales.make_scale (Text -> ScaleId
id_with Text
"pemade")
        (Instrument -> ScaleMap
inst_scale_map Instrument
pemade)
    , Doc -> Scale -> Scale
inst_doc Doc
"pemade" forall a b. (a -> b) -> a -> b
$ ScaleId -> ScaleMap -> Scale
BaliScales.make_scale (Text -> ScaleId
id_with Text
"pemade-b")
        (Instrument -> ScaleMap
inst_scale_map (Instrument -> Instrument
balinese_notation Instrument
pemade))
    , Doc -> Scale -> Scale
inst_doc Doc
"kantilan" forall a b. (a -> b) -> a -> b
$ ScaleId -> ScaleMap -> Scale
BaliScales.make_scale (Text -> ScaleId
id_with Text
"kantilan")
        (Instrument -> ScaleMap
inst_scale_map Instrument
kantilan)
    , Doc -> Scale -> Scale
inst_doc Doc
"kantilan" forall a b. (a -> b) -> a -> b
$ ScaleId -> ScaleMap -> Scale
BaliScales.make_scale (Text -> ScaleId
id_with Text
"kantilan-b")
        (Instrument -> ScaleMap
inst_scale_map (Instrument -> Instrument
balinese_notation Instrument
kantilan))
    ]
    where
    id_with :: Text -> ScaleId
id_with Text
suffix = Text -> ScaleId
Pitch.ScaleId forall a b. (a -> b) -> a -> b
$ forall a. Textlike a => a -> a -> a -> a
Texts.join2 Text
"-" Text
prefix Text
suffix
    inst_doc :: Doc -> Scale -> Scale
inst_doc Doc
name = Doc -> Scale -> Scale
Scales.add_doc forall a b. (a -> b) -> a -> b
$
        Doc
"This is centered around the " forall a. Semigroup a => a -> a -> a
<> Doc
name forall a. Semigroup a => a -> a -> a
<> Doc
" range."
    scale_map :: Format -> ScaleMap
scale_map Format
fmt = Config -> Format -> Maybe (Int, Int) -> ScaleMap
BaliScales.scale_map Config
config Format
fmt forall a. Maybe a
Nothing
    inst_scale_map :: Instrument -> ScaleMap
inst_scale_map = Config -> Instrument -> ScaleMap
BaliScales.instrument_scale_map Config
config

    complete_scale :: Format
complete_scale = Bool -> Key -> Keys -> Format
BaliScales.ioeua_relative Bool
True
        (Config -> Key
BaliScales.config_default_key Config
config) (Config -> Keys
BaliScales.config_keys Config
config)
    complete_scale_balinese :: Format
complete_scale_balinese =
        Degrees -> Bool -> Key -> Keys -> Format
BaliScales.digit_octave_relative Degrees
BaliScales.balinese Bool
True
            (Config -> Key
BaliScales.config_default_key Config
config)
            (Config -> Keys
BaliScales.config_keys Config
config)
    cipher_scale :: Format
cipher_scale = Int -> Key -> Keys -> Format
BaliScales.cipher_relative_dotted Int
5
        (Config -> Key
BaliScales.config_default_key Config
config)
        (Config -> Keys
BaliScales.config_keys Config
config)

jegog, calung, penyacah :: BaliScales.Instrument
jegog :: Instrument
jegog = Int -> Pitch -> Pitch -> Instrument
instrument Int
1 (forall pc. Enum pc => Int -> pc -> Pitch
Pitch.pitch Int
3 Pitch
I) (forall pc. Enum pc => Int -> pc -> Pitch
Pitch.pitch Int
3 Pitch
As)
calung :: Instrument
calung = Int -> Pitch -> Pitch -> Instrument
instrument Int
2 (forall pc. Enum pc => Int -> pc -> Pitch
Pitch.pitch Int
4 Pitch
I) (forall pc. Enum pc => Int -> pc -> Pitch
Pitch.pitch Int
4 Pitch
As)
penyacah :: Instrument
penyacah = Int -> Pitch -> Pitch -> Instrument
instrument Int
3 (forall pc. Enum pc => Int -> pc -> Pitch
Pitch.pitch Int
5 Integer
0) (forall pc. Enum pc => Int -> pc -> Pitch
Pitch.pitch Int
5 Pitch
As)

pemade, kantilan :: BaliScales.Instrument
pemade :: Instrument
pemade = Int -> Pitch -> Pitch -> Instrument
instrument Int
5 (forall pc. Enum pc => Int -> pc -> Pitch
Pitch.pitch Int
4 Pitch
O) (forall pc. Enum pc => Int -> pc -> Pitch
Pitch.pitch Int
6 Pitch
I)
kantilan :: Instrument
kantilan = Int -> Pitch -> Pitch -> Instrument
instrument Int
6 (forall pc. Enum pc => Int -> pc -> Pitch
Pitch.pitch Int
5 Pitch
O) (forall pc. Enum pc => Int -> pc -> Pitch
Pitch.pitch Int
7 Pitch
I)

instrument :: Pitch.Octave -> Pitch.Pitch -> Pitch.Pitch
    -> BaliScales.Instrument
instrument :: Int -> Pitch -> Pitch -> Instrument
instrument = Degrees -> RelativeOctaves -> Int -> Pitch -> Pitch -> Instrument
BaliScales.Instrument Degrees
BaliScales.ioeua RelativeOctaves
BaliScales.arrow_octaves

-- * config

balinese_notation :: BaliScales.Instrument -> BaliScales.Instrument
balinese_notation :: Instrument -> Instrument
balinese_notation Instrument
inst = Instrument
inst
    { inst_degrees :: Degrees
BaliScales.inst_degrees = Degrees
BaliScales.balinese
    , inst_relative_octaves :: RelativeOctaves
BaliScales.inst_relative_octaves = RelativeOctaves
BaliScales.balinese_octaves
    }

-- | These are from Tenzer's "Gamelan Gong Kebyar", page 29.  This is Dewa
-- Beratha's definition.  McPhee's book has different names for gambuh, but
-- Beratha's is probably more modern.
--
-- These are assigned with @key=...@.  McPhee calls them tekepan (suling) or
-- ambah.  Or I could use patutan / pathet.
config :: BaliScales.Config
config :: Config
config = BaliScales.Config
    { config_layout :: Layout
config_layout = Layout
layout
    , config_keys :: Keys
config_keys = Keys
all_keys
    , config_default_key :: Key
config_default_key = Key
default_key
    , config_laras :: LarasMap
config_laras = LarasMap
laras
    , config_default_laras :: Laras
config_default_laras = Laras
laras_rambat
    }
    where
    layout :: Layout
layout = [Int] -> Layout
Theory.layout [Int]
intervals
    Just Key
default_key = forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup (Text -> Key
Pitch.Key Text
"selisir") Keys
all_keys

intervals :: [Pitch.Semi]
intervals :: [Int]
intervals = [Int
1, Int
1, Int
2, Int
1, Int
2]

all_keys :: ChromaticScales.Keys
all_keys :: Keys
all_keys = forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList forall a b. (a -> b) -> a -> b
$ forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Int -> Text -> (Key, Key)
make [Int
0..]
    [ Text
"selisir"         -- 123_45_  ioe_ua_
    , Text
"slendro-gede"    -- _234_67  _ioe_ua
    , Text
"baro"            -- 1_345_7  a_ioe_u
    , Text
"tembung"         -- 12_456_  ua_ioe_
    , Text
"sunaren"         -- _23_567  _ua_ioe
    -- hypothetical
    , Text
"pengenter-alit"  -- 1_34_67  e_ua_io
    , Text
"pengenter"       -- 12_45_7  oe_ua_i
    ]
    where
    make :: Int -> Text -> (Key, Key)
make Int
tonic Text
name =
        ( Text -> Key
Pitch.Key Text
name
        , Degree -> Text -> [Int] -> Layout -> Key
Theory.key (Int -> Int -> Degree
Pitch.Degree Int
tonic Int
0) Text
name [Int]
intervals
            (Config -> Layout
BaliScales.config_layout Config
config)
        )

ugal_range, rambat_range, trompong_range, reyong_range :: Scale.Range
ugal_range :: Range
ugal_range = Pitch -> Pitch -> Range
Scale.Range (forall pc. Enum pc => Int -> pc -> Pitch
Pitch.pitch Int
3 Pitch
O) (forall pc. Enum pc => Int -> pc -> Pitch
Pitch.pitch Int
5 Pitch
I)
rambat_range :: Range
rambat_range = Pitch -> Pitch -> Range
Scale.Range (forall pc. Enum pc => Int -> pc -> Pitch
Pitch.pitch Int
3 Pitch
E) (forall pc. Enum pc => Int -> pc -> Pitch
Pitch.pitch Int
6 Pitch
I)
trompong_range :: Range
trompong_range = Pitch -> Pitch -> Range
Scale.Range (forall pc. Enum pc => Int -> pc -> Pitch
Pitch.pitch Int
3 Pitch
A) (forall pc. Enum pc => Int -> pc -> Pitch
Pitch.pitch Int
5 Pitch
U)
reyong_range :: Range
reyong_range = Pitch -> Pitch -> Range
Scale.Range (forall pc. Enum pc => Int -> pc -> Pitch
Pitch.pitch Int
4 Pitch
E) (forall pc. Enum pc => Int -> pc -> Pitch
Pitch.pitch Int
6 Pitch
U)

-- * laras

data Pitch = I | O | E | Es | U | A | As
    deriving (Pitch -> Pitch -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Pitch -> Pitch -> Bool
$c/= :: Pitch -> Pitch -> Bool
== :: Pitch -> Pitch -> Bool
$c== :: Pitch -> Pitch -> Bool
Eq, Eq Pitch
Pitch -> Pitch -> Bool
Pitch -> Pitch -> Ordering
Pitch -> Pitch -> Pitch
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Pitch -> Pitch -> Pitch
$cmin :: Pitch -> Pitch -> Pitch
max :: Pitch -> Pitch -> Pitch
$cmax :: Pitch -> Pitch -> Pitch
>= :: Pitch -> Pitch -> Bool
$c>= :: Pitch -> Pitch -> Bool
> :: Pitch -> Pitch -> Bool
$c> :: Pitch -> Pitch -> Bool
<= :: Pitch -> Pitch -> Bool
$c<= :: Pitch -> Pitch -> Bool
< :: Pitch -> Pitch -> Bool
$c< :: Pitch -> Pitch -> Bool
compare :: Pitch -> Pitch -> Ordering
$ccompare :: Pitch -> Pitch -> Ordering
Ord, Int -> Pitch
Pitch -> Int
Pitch -> [Pitch]
Pitch -> Pitch
Pitch -> Pitch -> [Pitch]
Pitch -> Pitch -> Pitch -> [Pitch]
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: Pitch -> Pitch -> Pitch -> [Pitch]
$cenumFromThenTo :: Pitch -> Pitch -> Pitch -> [Pitch]
enumFromTo :: Pitch -> Pitch -> [Pitch]
$cenumFromTo :: Pitch -> Pitch -> [Pitch]
enumFromThen :: Pitch -> Pitch -> [Pitch]
$cenumFromThen :: Pitch -> Pitch -> [Pitch]
enumFrom :: Pitch -> [Pitch]
$cenumFrom :: Pitch -> [Pitch]
fromEnum :: Pitch -> Int
$cfromEnum :: Pitch -> Int
toEnum :: Int -> Pitch
$ctoEnum :: Int -> Pitch
pred :: Pitch -> Pitch
$cpred :: Pitch -> Pitch
succ :: Pitch -> Pitch
$csucc :: Pitch -> Pitch
Enum, Int -> Pitch -> ShowS
[Pitch] -> ShowS
Pitch -> [Char]
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
showList :: [Pitch] -> ShowS
$cshowList :: [Pitch] -> ShowS
show :: Pitch -> [Char]
$cshow :: Pitch -> [Char]
showsPrec :: Int -> Pitch -> ShowS
$cshowsPrec :: Int -> Pitch -> ShowS
Show, Pitch
forall a. a -> a -> Bounded a
maxBound :: Pitch
$cmaxBound :: Pitch
minBound :: Pitch
$cminBound :: Pitch
Bounded)

laras :: Map Text BaliScales.Laras
laras :: LarasMap
laras = forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList forall a b. (a -> b) -> a -> b
$ forall a k. (a -> k) -> [a] -> [(k, a)]
Lists.keyOn Laras -> Text
BaliScales.laras_name forall a b. (a -> b) -> a -> b
$
    Laras
laras_rambat forall a. a -> [a] -> [a]
: [Laras]
mcphee

laras_rambat :: BaliScales.Laras
laras_rambat :: Laras
laras_rambat = Text
-> Pitch
-> ([NoteNumber] -> [NoteNumber])
-> Doc
-> [(NoteNumber, NoteNumber)]
-> Laras
BaliScales.laras Text
"rambat" Pitch
low_pitch (Int -> Pitch -> [NoteNumber] -> [NoteNumber]
extend Int
3 Pitch
E)
    Doc
"From my gender rambat, made in Blabatuh, Gianyar, tuned in\
    \ Munduk, Buleleng."
    [ (NoteNumber
51.03,   NoteNumber
51.85)  -- 3e, rambat begin
    , (NoteNumber
54.00NoteNumber -> Hz -> NoteNumber
-Hz
4, NoteNumber
54.00)  -- TODO
    , (NoteNumber
55.05,   NoteNumber
55.67)  -- 3u
    , (NoteNumber
56.10,   NoteNumber
56.50)  -- 3a, trompong begin
    , (NoteNumber
58.00NoteNumber -> Hz -> NoteNumber
-Hz
4, NoteNumber
58.00)  -- TODO

    , (NoteNumber
59.91,   NoteNumber
60.40)  -- 4i
    , (NoteNumber
61.80,   NoteNumber
62.41)  -- 4o, pemade begin
    , (NoteNumber
62.90,   NoteNumber
63.27)  -- 4e, reyong begin
    , (NoteNumber
65.00NoteNumber -> Hz -> NoteNumber
-Hz
4, NoteNumber
65.00)  -- TODO
    , (NoteNumber
67.15,   NoteNumber
67.48)  -- 4u
    , (NoteNumber
68.06,   NoteNumber
68.33)  -- 4a
    , (NoteNumber
70.00NoteNumber -> Hz -> NoteNumber
-Hz
4, NoteNumber
70.00)  -- TODO

    , (NoteNumber
71.88,   NoteNumber
72.15)  -- 5i
    , (NoteNumber
73.60,   NoteNumber
73.80)  -- 5o, kantilan begin
    , (NoteNumber
75.15,   NoteNumber
75.38)  -- 5e
    , (NoteNumber
78.00NoteNumber -> Hz -> NoteNumber
-Hz
4, NoteNumber
78.00)  -- TODO
    , (NoteNumber
79.12,   NoteNumber
79.28)  -- 5u, trompong end
    , (NoteNumber
80.27,   NoteNumber
80.26)  -- 5a
    , (NoteNumber
83.00NoteNumber -> Hz -> NoteNumber
-Hz
4, NoteNumber
83.00)  -- TODO

    , (NoteNumber
84.09,   NoteNumber
84.24)  -- 6i, rambat end, pemade end
    , (NoteNumber
86.08NoteNumber -> Hz -> NoteNumber
-Hz
4, NoteNumber
86.08)  -- 6o <- starts from reyong, which is more like isep
    , (NoteNumber
87.82NoteNumber -> Hz -> NoteNumber
-Hz
4, NoteNumber
87.82)  -- 6e
    , (NoteNumber
90.00NoteNumber -> Hz -> NoteNumber
-Hz
4, NoteNumber
90.00)  -- TODO
    , (NoteNumber
91.82NoteNumber -> Hz -> NoteNumber
-Hz
4, NoteNumber
91.82)  -- 6u, reyong end
    , (NoteNumber
92.50NoteNumber -> Hz -> NoteNumber
-Hz
4, NoteNumber
92.50)  -- 6a
    , (NoteNumber
95.00NoteNumber -> Hz -> NoteNumber
-Hz
4, NoteNumber
95.00)  -- TODO

    , (NoteNumber
96.46NoteNumber -> Hz -> NoteNumber
-Hz
4, NoteNumber
96.46)  -- 7i, kantilan end
    ]
    where
    NoteNumber
nn - :: NoteNumber -> Hz -> NoteNumber
- Hz
hz = Hz -> NoteNumber -> NoteNumber
Pitch.add_hz (-Hz
hz) NoteNumber
nn

allTunings :: [[Pitch.NoteNumber]]
allTunings :: [[NoteNumber]]
allTunings =
    -- rambat u, i,  reyong
    [ [NoteNumber
51.03, NoteNumber
51.85, NoteNumber
0]         -- 3e
    , [NoteNumber
55.05, NoteNumber
55.67, NoteNumber
0]
    , [NoteNumber
56.10, NoteNumber
56.50, NoteNumber
56.77]
    , [NoteNumber
59.91, NoteNumber
60.40, NoteNumber
60.83]     -- 4i
    , [NoteNumber
61.80, NoteNumber
62.41, NoteNumber
62.82]
    , [NoteNumber
62.90, NoteNumber
63.27, NoteNumber
63.36]
    , [NoteNumber
67.15, NoteNumber
67.48, NoteNumber
67.72]
    , [NoteNumber
68.06, NoteNumber
68.33, NoteNumber
68.35]
    , [NoteNumber
71.88, NoteNumber
72.15, NoteNumber
72.60]     -- 5i
    , [NoteNumber
73.60, NoteNumber
73.80, NoteNumber
74.09]
    , [NoteNumber
75.13, NoteNumber
75.38, NoteNumber
75.54]
    , [NoteNumber
79.12, NoteNumber
79.28, NoteNumber
79.45]
    , [NoteNumber
80.27, NoteNumber
80.26, NoteNumber
80.50]
    , [NoteNumber
84.09, NoteNumber
84.24, NoteNumber
84.53]     -- 6i
    , [    NoteNumber
0,     NoteNumber
0, NoteNumber
86.08]
    , [    NoteNumber
0,     NoteNumber
0, NoteNumber
87.82]
    , [    NoteNumber
0,     NoteNumber
0, NoteNumber
91.82]
    ]

-- | Extend down to 3i, which is jegog range.
extend :: Pitch.Octave -> Pitch -> [Pitch.NoteNumber] -> [Pitch.NoteNumber]
extend :: Int -> Pitch -> [NoteNumber] -> [NoteNumber]
extend Int
oct Pitch
pc = Int -> Pitch -> Pitch -> Pitch -> [NoteNumber] -> [NoteNumber]
Bali.extend_scale Int
7 Pitch
low_pitch Pitch
high_pitch (forall pc. Enum pc => Int -> pc -> Pitch
Pitch.pitch Int
oct Pitch
pc)

-- | Lowest note starts on this octave.
base_octave :: Pitch.Octave
base_octave :: Int
base_octave = Int
3

low_pitch, high_pitch :: Pitch.Pitch
low_pitch :: Pitch
low_pitch = forall pc. Enum pc => Int -> pc -> Pitch
Pitch.pitch Int
base_octave Pitch
I
high_pitch :: Pitch
high_pitch = forall pc. Enum pc => Int -> pc -> Pitch
Pitch.pitch Int
7 Pitch
I

mcphee :: [BaliScales.Laras]
mcphee :: [Laras]
mcphee = forall a b. (a -> b) -> [a] -> [b]
map ((Text, ([NoteNumber], Doc)) -> Laras
make forall b c a. (b -> c) -> (a -> b) -> a -> c
. Pitch -> Pitch -> Laras -> (Text, ([NoteNumber], Doc))
McPhee.extract Pitch
low_pitch Pitch
high_pitch) [Laras]
McPhee.saih_pitu
    where
    make :: (Text, ([NoteNumber], Doc)) -> Laras
make (Text
name, ([NoteNumber]
nns, Doc
doc)) =
        Text
-> Pitch
-> ([NoteNumber] -> [NoteNumber])
-> Doc
-> [(NoteNumber, NoteNumber)]
-> Laras
BaliScales.laras Text
name Pitch
low_pitch forall a. a -> a
id Doc
doc
            (forall a b. (a -> b) -> [a] -> [b]
map (\NoteNumber
nn -> (NoteNumber
nn, NoteNumber
nn)) [NoteNumber]
nns)

-- * instrument integration

-- | A Scale with the entire theoretical range.  This is for instruments
-- that are normalized to 12tet and then tuned in the patch (e.g. using KSP).
complete_instrument_scale :: BaliScales.Laras -> BaliScales.Tuning
    -> Patch.Scale
complete_instrument_scale :: Laras -> Tuning -> Scale
complete_instrument_scale = ([(Key, NoteNumber)] -> [(Key, NoteNumber)])
-> Laras -> Tuning -> Scale
instrument_scale forall a. a -> a
id

instrument_scale ::
    ([(Midi.Key, Pitch.NoteNumber)] -> [(Midi.Key, Pitch.NoteNumber)])
    -- ^ drop and take keys for the instrument's range
    -> BaliScales.Laras -> BaliScales.Tuning -> Patch.Scale
instrument_scale :: ([(Key, NoteNumber)] -> [(Key, NoteNumber)])
-> Laras -> Tuning -> Scale
instrument_scale =
    Text
-> [Key]
-> ([(Key, NoteNumber)] -> [(Key, NoteNumber)])
-> Laras
-> Tuning
-> Scale
make_instrument_scale Text
"legong" -- i o e e# u a a#
        [Key
Key.c_1, Key
Key.d_1, Key
Key.e_1, Key
Key.f_1, Key
Key.g_1, Key
Key.a_1, Key
Key.b_1]

make_instrument_scale :: Text -> [Midi.Key]
    -> ([(Midi.Key, Pitch.NoteNumber)] -> [(Midi.Key, Pitch.NoteNumber)])
    -- ^ drop and take keys for the instrument's range
    -> BaliScales.Laras -> BaliScales.Tuning -> Patch.Scale
make_instrument_scale :: Text
-> [Key]
-> ([(Key, NoteNumber)] -> [(Key, NoteNumber)])
-> Laras
-> Tuning
-> Scale
make_instrument_scale Text
name [Key]
keys [(Key, NoteNumber)] -> [(Key, NoteNumber)]
take_range Laras
laras Tuning
tuning =
    Text -> [(Key, NoteNumber)] -> Scale
Patch.make_scale (Text
name forall a. Semigroup a => a -> a -> a
<> Text
" " forall a. Semigroup a => a -> a -> a
<> forall a. ShowVal a => a -> Text
ShowVal.show_val Tuning
tuning) forall a b. (a -> b) -> a -> b
$
        [(Key, NoteNumber)] -> [(Key, NoteNumber)]
take_range forall a b. (a -> b) -> a -> b
$ forall a b. [a] -> [b] -> [(a, b)]
zip ([Key] -> [Key]
midi_keys [Key]
keys) (forall a. Vector a -> [a]
Vector.toList Vector NoteNumber
nns)
    where
    nns :: Vector NoteNumber
nns = case Tuning
tuning of
        Tuning
BaliScales.Umbang -> Laras -> Vector NoteNumber
BaliScales.laras_umbang Laras
laras
        Tuning
BaliScales.Isep -> Laras -> Vector NoteNumber
BaliScales.laras_isep Laras
laras

-- | Emit from i3 on up.
midi_keys :: [Midi.Key] -> [Midi.Key]
midi_keys :: [Key] -> [Key]
midi_keys [Key]
keys = forall {a}. [a] -> [a]
trim forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap forall {a}. Integral a => a -> [Key]
octave_keys [Int
base_octave forall a. Num a => a -> a -> a
+ Int
1 ..]
    -- base_octave + 1 because MIDI starts at octave -1
    where
    trim :: [a] -> [a]
trim = forall a. Int -> [a] -> [a]
take (Int
5 forall a. Num a => a -> a -> a
* forall (t :: * -> *) a. Foldable t => t a -> Int
length [Key]
keys forall a. Num a => a -> a -> a
+ Int
1)
    octave_keys :: a -> [Key]
octave_keys a
oct = forall a b. (a -> b) -> [a] -> [b]
map (forall a. Integral a => a -> Key
Midi.to_key (a
oct forall a. Num a => a -> a -> a
* a
12) +) [Key]
keys