hmt-0.15: Haskell Music Theory

Safe Haskell | Safe
Language | Haskell98

Music.Theory.Tuning.Scala

Description

Parser for the Scala scale file format. See http://www.huygens-fokker.org/scala/scl_format.html for details. This module succesfully parses all 4496 scales in v.81 of the scale library.

Synopsis

- type Pitch i = Either Cents (Ratio i)
- type Scale i = (String, i, [Pitch i])
- scale_description :: Scale i -> String
- scale_degree :: Scale i -> i
- scale_pitches :: Scale i -> [Pitch i]
- scale_octave :: Scale i -> Maybe (Pitch i)
- perfect_octave :: Integral i => Scale i -> Bool
- scale_pitch_representations :: Integral t => Scale i -> (t, t)
- pitch_cents :: Pitch Integer -> Cents
- type Epsilon = Double
- pitch_ratio :: Epsilon -> Pitch Integer -> Rational
- scale_uniform :: Epsilon -> Scale Integer -> Scale Integer
- scale_cents :: Scale Integer -> [Cents]
- scale_ratios :: Epsilon -> Scale Integer -> [Rational]
- comment_p :: String -> Bool
- filter_cr :: String -> String
- p_or :: [a -> Bool] -> a -> Bool
- remove_eol_comments :: String -> String
- filter_comments :: [String] -> [String]
- delete_trailing_point :: String -> String
- pitch :: (Read i, Integral i) => String -> Pitch i
- pitch_ln :: (Read i, Integral i) => String -> Pitch i
- parse :: (Read i, Integral i) => String -> Scale i
- load :: (Read i, Integral i) => FilePath -> IO (Scale i)
- dir_subset :: [String] -> FilePath -> IO [FilePath]
- load_dir :: (Read i, Integral i) => FilePath -> IO [Scale i]

# Documentation

type Pitch i = Either Cents (Ratio i) Source #

A `.scl` pitch is either in `Cents` or is a `Ratio`.

type Scale i = (String, i, [Pitch i]) Source #

A scale has a description, a degree, and a list of `Pitch`es.

scale_description :: Scale i -> String Source #

Text description of scale.

scale_degree :: Scale i -> i Source #

The degree of the scale (number of `Pitch`es).

scale_pitches :: Scale i -> [Pitch i] Source #

The `Pitch`es at `Scale`.

scale_octave :: Scale i -> Maybe (Pitch i) Source #

The last `Pitch` element of the scale (ie. the ocatve).

perfect_octave :: Integral i => Scale i -> Bool Source #

Is `scale_octave` perfect, ie. `Ratio` of `2` or `Cents` of `1200`.

scale_pitch_representations :: Integral t => Scale i -> (t, t) Source #

A pair giving the number of `Cents` and number of `Ratio` pitches at `Scale`.

pitch_cents :: Pitch Integer -> Cents Source #

Pitch as `Cents`, conversion by `to_cents_r` if necessary.

type Epsilon = Double Source #

pitch_ratio :: Epsilon -> Pitch Integer -> Rational Source #

Pitch as `Rational`, conversion by `reconstructed_ratio` if necessary, hence epsilon.

scale_uniform :: Epsilon -> Scale Integer -> Scale Integer Source #

Make scale pitches uniform, conforming to the most promininent pitch type.

scale_cents :: Scale Integer -> [Cents] Source #

Scale as list of `Cents` (ie. `pitch_cents`) with `0` prefix.

scale_ratios :: Epsilon -> Scale Integer -> [Rational] Source #

Scale as list of `Rational` (ie. `pitch_ratio`) with `1` prefix.

comment_p :: String -> Bool Source #

Comment lines being with `!`.

filter_cr :: String -> String Source #

Remove `r`.

p_or :: [a -> Bool] -> a -> Bool Source #

Logical or of list of predicates.

remove_eol_comments :: String -> String Source #

Remove to end of line `!` comments.

filter_comments :: [String] -> [String] Source #

Remove comments and null lines.

    filter_comments ["!a","b","","c"] == ["b","c"]

delete_trailing_point :: String -> String Source #

Delete trailing `.`, `read` fails for `700.`.

pitch :: (Read i, Integral i) => String -> Pitch i Source #

Pitches are either cents (with decimal point) or ratios (with `/`).

    map pitch ["700.0","3/2","2"] == [Left 700,Right (3/2),Right 2]

pitch_ln :: (Read i, Integral i) => String -> Pitch i Source #

Pitch lines may contain commentary.

parse :: (Read i, Integral i) => String -> Scale i Source #

Parse `.scl` file.

load :: (Read i, Integral i) => FilePath -> IO (Scale i) Source #

Load `.scl` file.

    s <- load "/home/rohan/data/scala/81/scl/xenakis_chrom.scl"
    scale_pitch_representations s == (6,1)
    scale_ratios 1e-3 s == [1,21/20,29/23,179/134,280/187,11/7,100/53,2]

dir_subset :: [String] -> FilePath -> IO [FilePath] Source #

Subset of files in dir with an extension in ext.

load_dir :: (Read i, Integral i) => FilePath -> IO [Scale i] Source #

Load all `.scl` files at dir.

    db <- load_dir "/home/rohan/data/scala/81/scl"
    length db == 4496
    length (filter ((== 0) . scale_degree) db) == 0
    length (filter (== Just (Right 2)) (map scale_octave db)) == 3855

    let r = [2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24
            ,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44
            ,45,46,47,48,49,50,51,53,54,55,56,57,58,59,60,61,62,63,64
            ,65,66,67,68,69,70,71,72,74,75,77,78,79,80,81,84,87,88
            ,90,91,92,95,96,99,100,101,105,110,112,117,118,130,140,171
            ,180,271,311,342,366,441,612]
    in nub (sort (map scale_degree db)) == r

    let r = ["Xenakis's Byzantine Liturgical mode, 5 + 19 + 6 parts"
            ,"Xenakis's Byzantine Liturgical mode, 12 + 11 + 7 parts"
            ,"Xenakis's Byzantine Liturgical mode, 7 + 16 + 7 parts"]
    in filter (isInfixOf "Xenakis") (map scale_description db) == r

    length (filter (not . perfect_octave) db) == 544

    mapM_ (putStrLn.scale_description) (filter (not . perfect_octave) db)