{- | Starting-point data for a new document: the 'Song' the editor opens
with ('defaultSong'), and the filler beats used when a new 'Measure' is
inserted into an existing track ('defaultMeasureBeats').
-}
module Termtab.Defaults (defaultSong, defaultMeasureBeats) where

import Data.Map.Strict qualified as Map

import Termtab.Types

-- Standard 6-string guitar tuning, low to high: E2 A2 D3 G3 B3 E4
standardTuning :: [Pitch]
standardTuning :: [Pitch]
standardTuning = (Int -> Pitch) -> [Int] -> [Pitch]
forall a b. (a -> b) -> [a] -> [b]
map Int -> Pitch
Pitch [Int
40, Int
45, Int
50, Int
55, Int
59, Int
64]

{- | The 'Song' a new document starts as: one 6-string guitar track with a
single demo measure ('defaultTrack'), one 4\/4 measure of metadata
('defaultMeasure'), at 120 BPM.
-}
defaultSong :: Song
defaultSong :: Song
defaultSong =
    Song
        { songTitle :: Text
songTitle = Text
"Untitled"
        , songArtist :: Text
songArtist = Text
""
        , songTempo :: Tempo
songTempo = Int -> Tempo
Tempo Int
120
        , songTracks :: [Track]
songTracks = [Track
defaultTrack]
        , songMeasures :: [Measure]
songMeasures = [Measure
defaultMeasure]
        }

{- | A single guitar track containing one measure of demo notes (a rising
E-major-ish arpeggio), used by 'defaultSong'.
-}
defaultTrack :: Track
defaultTrack :: Track
defaultTrack =
    Track
        { trackName :: Text
trackName = Text
"Guitar"
        , trackInstrument :: Instrument
trackInstrument = Guitar{tuning :: [Pitch]
tuning = [Pitch]
standardTuning, stringCount :: Int
stringCount = Int
6}
        , trackChannel :: MidiChannel
trackChannel = Int -> MidiChannel
MidiChannel Int
0
        , trackBeats :: Map MeasureIndex [Beat]
trackBeats =
            MeasureIndex -> [Beat] -> Map MeasureIndex [Beat]
forall k a. k -> a -> Map k a
Map.singleton (Int -> MeasureIndex
MeasureIndex Int
0) ([Beat] -> Map MeasureIndex [Beat])
-> [Beat] -> Map MeasureIndex [Beat]
forall a b. (a -> b) -> a -> b
$
                [ Duration -> [(Int, Int, Int)] -> Beat
mkBeat Duration
Quarter [(Int
5, Int
0, Int
40), (Int
4, Int
2, Int
47)] -- E2 + B2
                , Duration -> [(Int, Int, Int)] -> Beat
mkBeat Duration
Quarter [(Int
3, Int
2, Int
52)] -- E3
                , Duration -> [(Int, Int, Int)] -> Beat
mkBeat Duration
Quarter [(Int
2, Int
0, Int
55)] -- G3
                , Duration -> [(Int, Int, Int)] -> Beat
mkBeat Duration
Quarter [(Int
1, Int
3, Int
62), (Int
0, Int
0, Int
64)] -- D4 + E4
                ]
        }

{- | Build a 'Beat' from @(string, fret, pitch)@ triples, defaulting
'noteVelocity' to 100 and 'noteEffects' to none. Used only to keep
'defaultTrack' concise.
-}
mkBeat :: Duration -> [(Int, Int, Int)] -> Beat
mkBeat :: Duration -> [(Int, Int, Int)] -> Beat
mkBeat Duration
dur [(Int, Int, Int)]
notes =
    Beat
        { beatDuration :: Duration
beatDuration = Duration
dur
        , beatNotes :: [Note]
beatNotes =
            [ Note
                { notePitch :: Pitch
notePitch = Int -> Pitch
Pitch Int
pitch
                , noteVelocity :: Velocity
noteVelocity = Int -> Velocity
Velocity Int
100
                , noteEffects :: [NoteEffect]
noteEffects = []
                , noteString :: Maybe StringIndex
noteString = StringIndex -> Maybe StringIndex
forall a. a -> Maybe a
Just (Int -> StringIndex
StringIndex Int
s)
                , noteFret :: Maybe FretNumber
noteFret = FretNumber -> Maybe FretNumber
forall a. a -> Maybe a
Just (Int -> FretNumber
FretNumber Int
f)
                }
            | (Int
s, Int
f, Int
pitch) <- [(Int, Int, Int)]
notes
            ]
        , beatIsRest :: Bool
beatIsRest = Bool
False
        }

-- | Generate the initial beat list for a time signature (all quarter rests).
defaultMeasureBeats :: TimeSignature -> [Beat]
defaultMeasureBeats :: TimeSignature -> [Beat]
defaultMeasureBeats (TimeSignature Int
num Int
_) =
    Int -> Beat -> [Beat]
forall a. Int -> a -> [a]
replicate Int
num Beat{beatDuration :: Duration
beatDuration = Duration
Quarter, beatNotes :: [Note]
beatNotes = [], beatIsRest :: Bool
beatIsRest = Bool
True}

{- | The single 4\/4, C-major measure that starts off 'songMeasures' in
'defaultSong'.
-}
defaultMeasure :: Measure
defaultMeasure :: Measure
defaultMeasure =
    Measure
        { measureIndex :: MeasureIndex
measureIndex = Int -> MeasureIndex
MeasureIndex Int
0
        , timeSignature :: TimeSignature
timeSignature = Int -> Int -> TimeSignature
TimeSignature Int
4 Int
4
        , keySignature :: KeySignature
keySignature = Int -> Mode -> KeySignature
KeySignature Int
0 Mode
Major
        , tempoChange :: Maybe Tempo
tempoChange = Maybe Tempo
forall a. Maybe a
Nothing
        }