{- | Functions for reading midi note data (Mnd) from Csv files.

This is /not/ a generic text midi notation.
The required columns are documented at `Mnd` and `Mndd`.
The defined commands are @on@ and @off@, but others may be present.
Non-integral note number and key velocity data are allowed.
-}
module Music.Theory.Array.Csv.Midi.Mnd where

import Data.Function {- base -}
import Data.List {- base -}
import Data.Maybe {- base -}

import Data.List.Split {- split -}

import qualified Music.Theory.Array.Csv as T {- hmt-base -}
import qualified Music.Theory.Math as T {- hmt-base -}
import qualified Music.Theory.Read as T {- hmt-base -}
import qualified Music.Theory.Show as T {- hmt-base -}

import qualified Music.Theory.Time.Seq as T {- hmt -}

-- * Param ; Sound.SC3.Server.Param

type Param = [(String,Double)]

param_parse :: (Char,Char) -> String -> Param
param_parse :: (Char, Char) -> String -> Param
param_parse (Char
c1,Char
c2) String
str =
    let f :: String -> (String, b)
f String
x = case forall a. Eq a => [a] -> [a] -> [[a]]
splitOn [Char
c2] String
x of
                [String
lhs,String
rhs] -> (String
lhs,forall a. Read a => String -> a
read String
rhs)
                [String]
_ -> forall a. HasCallStack => String -> a
error (String
"param_parse: " forall a. [a] -> [a] -> [a]
++ String
x)
    in if forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
str then [] else forall a b. (a -> b) -> [a] -> [b]
map forall {b}. Read b => String -> (String, b)
f (forall a. Eq a => [a] -> [a] -> [[a]]
splitOn [Char
c1] String
str)

param_pp :: (Char,Char) -> Int -> Param -> String
param_pp :: (Char, Char) -> Int -> Param -> String
param_pp (Char
c1,Char
c2) Int
k =
    let f :: (String, Double) -> String
f (String
lhs,Double
rhs) = forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String
lhs,[Char
c2],Int -> Double -> String
T.double_pp Int
k Double
rhs]
    in forall a. [a] -> [[a]] -> [a]
intercalate [Char
c1] forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map (String, Double) -> String
f

-- * Mnd

-- | If /r/ is whole to /k/ places then show as integer, else as float to /k/ places.
data_value_pp :: Real t => Int -> t -> String
data_value_pp :: forall t. Real t => Int -> t -> String
data_value_pp Int
k t
r =
    if forall r. Real r => Int -> r -> Bool
T.whole_to_precision Int
k t
r
    then forall a. Show a => a -> String
show (forall r. Real r => r -> Int
T.real_floor_int t
r)
    else forall t. Real t => Int -> t -> String
T.real_pp Int
k t
r

-- | Channel values are 4-bit (0-15).
type Channel = Int

-- | The required header (column names) field.
csv_mnd_hdr :: [String]
csv_mnd_hdr :: [String]
csv_mnd_hdr = [String
"time",String
"on/off",String
"note",String
"velocity",String
"channel",String
"param"]

{- | Midi note data, the type parameters are to allow for fractional note & velocity values.

The command is a string, @on@ and @off@ are standard, other commands may be present.
note and velocity data is (0-127), channel is (0-15), param are ;-separated key:string=value:float.

> unwords csv_mnd_hdr == "time on/off note velocity channel param"

> all_notes_off = zipWith (\t k -> (t,"off",k,0,0,[])) [0.0,0.01 ..] [0 .. 127]
> csv_mnd_write 4 "/home/rohan/sw/hmt/data/csv/mnd/all-notes-off.csv" all_notes_off
-}
type Mnd t n = (t,String,n,n,Channel,Param)

csv_mnd_parse_f :: (Read t,Real t,Read n,Real n) => (n -> m) -> T.Csv_Table String -> [Mnd t m]
csv_mnd_parse_f :: forall t n m.
(Read t, Real t, Read n, Real n) =>
(n -> m) -> Csv_Table String -> [Mnd t m]
csv_mnd_parse_f n -> m
cnv (Maybe [String]
hdr,Table String
dat) =
    let err :: String -> a
err String
x = forall a. HasCallStack => String -> a
error (String
"csv_mnd_read: " forall a. [a] -> [a] -> [a]
++ String
x)
        f :: [String] -> (a, String, m, m, e, Param)
f [String]
m = case [String]
m of
                [String
st,String
msg,String
mnn,String
vel,String
ch,String
pm] ->
                    (forall a. Read a => String -> String -> a
T.reads_exact_err String
"time:real" String
st
                    ,String
msg
                    ,n -> m
cnv (forall a. Read a => String -> String -> a
T.reads_exact_err String
"note:real" String
mnn)
                    ,n -> m
cnv (forall a. Read a => String -> String -> a
T.reads_exact_err String
"velocity:real" String
vel)
                    ,forall a. Read a => String -> String -> a
T.reads_exact_err String
"channel:int" String
ch
                    ,(Char, Char) -> String -> Param
param_parse (Char
';',Char
'=') String
pm)
                [String]
_ -> forall {a}. String -> a
err String
"entry?"
    in case Maybe [String]
hdr of
         Just [String]
hdr' -> if [String]
hdr' forall a. Eq a => a -> a -> Bool
== [String]
csv_mnd_hdr then forall a b. (a -> b) -> [a] -> [b]
map forall {a} {e}.
(Read a, Read e) =>
[String] -> (a, String, m, m, e, Param)
f Table String
dat else forall {a}. String -> a
err String
"header?"
         Maybe [String]
Nothing -> forall {a}. String -> a
err String
"no header?"

csv_mnd_parse :: (Read t,Real t,Read n,Real n) => T.Csv_Table String -> [Mnd t n]
csv_mnd_parse :: forall t n.
(Read t, Real t, Read n, Real n) =>
Csv_Table String -> [Mnd t n]
csv_mnd_parse = forall t n m.
(Read t, Real t, Read n, Real n) =>
(n -> m) -> Csv_Table String -> [Mnd t m]
csv_mnd_parse_f forall a. a -> a
id

load_csv :: FilePath -> IO (T.Csv_Table String)
load_csv :: String -> IO (Csv_Table String)
load_csv = forall a. Csv_Opt -> (String -> a) -> String -> IO (Csv_Table a)
T.csv_table_read (Bool
True,Char
',',Bool
False,Csv_Align_Columns
T.Csv_No_Align) forall a. a -> a
id

-- | Midi note data.
--
-- > let fn = "/home/rohan/cvs/uc/uc-26/daily-practice/2014-08-13.1.csv"
-- > let fn = "/home/rohan/sw/hmt/data/csv/mnd/1080-C01.csv"
-- > m <- csv_mnd_read fn :: IO [Mnd Double Int]
-- > length m -- 1800 17655
-- > csv_mnd_write 4 "/tmp/t.csv" m
csv_mnd_read :: (Read t,Real t,Read n,Real n) => FilePath -> IO [Mnd t n]
csv_mnd_read :: forall t n.
(Read t, Real t, Read n, Real n) =>
String -> IO [Mnd t n]
csv_mnd_read = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall t n.
(Read t, Real t, Read n, Real n) =>
Csv_Table String -> [Mnd t n]
csv_mnd_parse forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO (Csv_Table String)
load_csv

-- | Writer.
csv_mnd_write :: (Real t,Real n) => Int -> FilePath -> [Mnd t n] -> IO ()
csv_mnd_write :: forall t n. (Real t, Real n) => Int -> String -> [Mnd t n] -> IO ()
csv_mnd_write Int
r_prec String
nm =
    let un_node :: (t, String, t, t, a, Param) -> [String]
un_node (t
st,String
msg,t
mnn,t
vel,a
ch,Param
pm) =
            [forall t. Real t => Int -> t -> String
T.real_pp Int
r_prec t
st
            ,String
msg
            ,forall t. Real t => Int -> t -> String
data_value_pp Int
r_prec t
mnn
            ,forall t. Real t => Int -> t -> String
data_value_pp Int
r_prec t
vel
            ,forall a. Show a => a -> String
show a
ch
            ,(Char, Char) -> Int -> Param -> String
param_pp (Char
';',Char
'=') Int
r_prec Param
pm]
        with_hdr :: b -> (Maybe [String], b)
with_hdr b
dat = (forall a. a -> Maybe a
Just [String]
csv_mnd_hdr,b
dat)
    in forall a.
(a -> String) -> Csv_Opt -> String -> Csv_Table a -> IO ()
T.csv_table_write forall a. a -> a
id Csv_Opt
T.def_csv_opt String
nm forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {b}. b -> (Maybe [String], b)
with_hdr forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map forall {t} {t} {t} {a}.
(Real t, Real t, Real t, Show a) =>
(t, String, t, t, a, Param) -> [String]
un_node

-- * Mnd Seq forms

-- | (p0=midi-note,p1=velocity,channel,param)
type Event n = (n,n,Channel,Param)

-- | mnn = midi-note-number
event_mnn :: Event t -> t
event_mnn :: forall t. Event t -> t
event_mnn (t
mnn,t
_,Int
_,Param
_) = t
mnn

-- | ch = channel
event_ch :: Event t -> Channel
event_ch :: forall t. Event t -> Int
event_ch (t
_,t
_,Int
ch,Param
_) = Int
ch

-- | Are events equal at mnn field?
event_eq_mnn :: Eq t => Event t -> Event t -> Bool
event_eq_mnn :: forall t. Eq t => Event t -> Event t -> Bool
event_eq_mnn = forall a. Eq a => a -> a -> Bool
(==) forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` forall t. Event t -> t
event_mnn

-- | Are events equal at mnn and ch fields?
event_eq_ol :: Eq t => Event t -> Event t -> Bool
event_eq_ol :: forall t. Eq t => Event t -> Event t -> Bool
event_eq_ol = forall a. Eq a => a -> a -> Bool
(==) forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` (\(t
mnn,t
_,Int
ch,Param
_) -> (t
mnn,Int
ch))

-- | Apply (mnn-f,vel-f,ch-f,param-f) to Event.
event_map :: (t -> u,t -> u,Channel -> Channel,Param -> Param) -> Event t -> Event u
event_map :: forall t u.
(t -> u, t -> u, Int -> Int, Param -> Param) -> Event t -> Event u
event_map (t -> u
f1,t -> u
f2,Int -> Int
f3,Param -> Param
f4) (t
mnn,t
vel,Int
ch,Param
param) = (t -> u
f1 t
mnn,t -> u
f2 t
vel,Int -> Int
f3 Int
ch,Param -> Param
f4 Param
param)

-- | Apply /f/ at mnn and vel fields.
event_cast :: (t -> u) -> Event t -> Event u
event_cast :: forall t u. (t -> u) -> Event t -> Event u
event_cast t -> u
f = forall t u.
(t -> u, t -> u, Int -> Int, Param -> Param) -> Event t -> Event u
event_map (t -> u
f,t -> u
f,forall a. a -> a
id,forall a. a -> a
id)

-- | Add /x/ to mnn field.
event_transpose :: Num a => a -> Event a -> Event a
event_transpose :: forall a. Num a => a -> Event a -> Event a
event_transpose a
x = forall t u.
(t -> u, t -> u, Int -> Int, Param -> Param) -> Event t -> Event u
event_map (forall a. Num a => a -> a -> a
(+) a
x,forall a. a -> a
id,forall a. a -> a
id,forall a. a -> a
id)

-- | Translate from 'Tseq' form to 'Wseq' form.
midi_tseq_to_midi_wseq :: (Num t,Eq n) => T.Tseq t (T.Begin_End (Event n)) -> T.Wseq t (Event n)
midi_tseq_to_midi_wseq :: forall t n.
(Num t, Eq n) =>
Tseq t (Begin_End (Event n)) -> Wseq t (Event n)
midi_tseq_to_midi_wseq = forall t a.
Num t =>
(a -> a -> Bool) -> Tseq t (Begin_End a) -> Wseq t a
T.tseq_begin_end_to_wseq (\(n
n0,n
_,Int
c0,Param
_) (n
n1,n
_,Int
c1,Param
_) -> Int
c0 forall a. Eq a => a -> a -> Bool
== Int
c1 Bool -> Bool -> Bool
&& n
n0 forall a. Eq a => a -> a -> Bool
== n
n1)

midi_wseq_to_midi_tseq :: (Num t,Ord t) => T.Wseq t x -> T.Tseq t (T.Begin_End x)
midi_wseq_to_midi_tseq :: forall t x. (Num t, Ord t) => Wseq t x -> Tseq t (Begin_End x)
midi_wseq_to_midi_tseq = forall t x. (Num t, Ord t) => Wseq t x -> Tseq t (Begin_End x)
T.wseq_begin_end

-- | Ignores non on/off messages.
mnd_to_tseq :: Num n => [Mnd t n] -> T.Tseq t (T.Begin_End (Event n))
mnd_to_tseq :: forall n t. Num n => [Mnd t n] -> Tseq t (Begin_End (Event n))
mnd_to_tseq =
    let mk_node :: (a, String, a, b, c, d) -> Maybe (a, Begin_End (a, b, c, d))
mk_node (a
st,String
msg,a
mnn,b
vel,c
ch,d
pm) =
            case String
msg of
              String
"on" -> forall a. a -> Maybe a
Just (a
st,forall a. a -> Begin_End a
T.Begin (a
mnn,b
vel,c
ch,d
pm))
              String
"off" -> forall a. a -> Maybe a
Just (a
st,forall a. a -> Begin_End a
T.End (a
mnn,b
0,c
ch,d
pm))
              String
_ -> forall a. Maybe a
Nothing
    in forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe forall {b} {a} {a} {c} {d}.
Num b =>
(a, String, a, b, c, d) -> Maybe (a, Begin_End (a, b, c, d))
mk_node

-- | 'Tseq' form of 'csv_mnd_read', channel information is retained, off-velocity is zero.
csv_mnd_read_tseq :: (Read t,Real t,Read n,Real n) => FilePath -> IO (T.Tseq t (T.Begin_End (Event n)))
csv_mnd_read_tseq :: forall t n.
(Read t, Real t, Read n, Real n) =>
String -> IO (Tseq t (Begin_End (Event n)))
csv_mnd_read_tseq = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall n t. Num n => [Mnd t n] -> Tseq t (Begin_End (Event n))
mnd_to_tseq forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall t n.
(Read t, Real t, Read n, Real n) =>
String -> IO [Mnd t n]
csv_mnd_read

-- | 'Tseq' form of 'csv_mnd_write', data is .
csv_mnd_write_tseq :: (Real t,Real n) => Int -> FilePath -> T.Tseq t (T.Begin_End (Event n)) -> IO ()
csv_mnd_write_tseq :: forall t n.
(Real t, Real n) =>
Int -> String -> Tseq t (Begin_End (Event n)) -> IO ()
csv_mnd_write_tseq Int
r_prec String
nm Tseq t (Begin_End (Event n))
sq =
    let f :: (a, Begin_End (c, d, e, f)) -> (a, String, c, d, e, f)
f (a
t,Begin_End (c, d, e, f)
e) = case Begin_End (c, d, e, f)
e of
                    T.Begin (c
n,d
v,e
c,f
p) -> (a
t,String
"on",c
n,d
v,e
c,f
p)
                    T.End (c
n,d
_,e
c,f
p) -> (a
t,String
"off",c
n,d
0,e
c,f
p)
    in forall t n. (Real t, Real n) => Int -> String -> [Mnd t n] -> IO ()
csv_mnd_write Int
r_prec String
nm (forall a b. (a -> b) -> [a] -> [b]
map forall {d} {a} {c} {e} {f}.
Num d =>
(a, Begin_End (c, d, e, f)) -> (a, String, c, d, e, f)
f Tseq t (Begin_End (Event n))
sq)

-- * Mndd (simplifies cases where overlaps on the same channel are allowed).

-- | Message should be @note@ for note data.
csv_mndd_hdr :: [String]
csv_mndd_hdr :: [String]
csv_mndd_hdr = [String
"time",String
"duration",String
"message",String
"note",String
"velocity",String
"channel",String
"param"]

-- | Midi note/duration data.
-- The type parameters are to allow for fractional note & velocity values.
-- The command is a string, @note@ is standard, other commands may be present.
--
-- > unwords csv_mndd_hdr == "time duration message note velocity channel param"
type Mndd t n = (t,t,String,n,n,Channel,Param)

-- | Compare sequence is: start-time,channel-number,note-number,velocity,duration,param.
mndd_compare :: (Ord t,Ord n) => Mndd t n -> Mndd t n -> Ordering
mndd_compare :: forall t n. (Ord t, Ord n) => Mndd t n -> Mndd t n -> Ordering
mndd_compare Mndd t n
x1 Mndd t n
x2 =
  case (Mndd t n
x1,Mndd t n
x2) of
    ((t
t1,t
d1,String
"note",n
n1,n
v1,Int
c1,Param
p1),(t
t2,t
d2,String
"note",n
n2,n
v2,Int
c2,Param
p2)) ->
      forall a. Ord a => a -> a -> Ordering
compare (t
t1,Int
c1,n
n1,n
v1,t
d1,Param
p1) (t
t2,Int
c2,n
n2,n
v2,t
d2,Param
p2)
    (Mndd t n, Mndd t n)
_ -> forall a. Ord a => a -> a -> Ordering
compare Mndd t n
x1 Mndd t n
x2

csv_mndd_parse_f :: (Read t,Real t,Read n,Real n) => (n -> m) -> T.Csv_Table String -> [Mndd t m]
csv_mndd_parse_f :: forall t n m.
(Read t, Real t, Read n, Real n) =>
(n -> m) -> Csv_Table String -> [Mndd t m]
csv_mndd_parse_f n -> m
cnv (Maybe [String]
hdr,Table String
dat) =
    let err :: String -> a
err String
x = forall a. HasCallStack => String -> a
error (String
"csv_mndd_read: " forall a. [a] -> [a] -> [a]
++ String
x)
        f :: [String] -> (a, b, String, m, m, f, Param)
f [String]
m =
            case [String]
m of
              [String
st,String
du,String
msg,String
mnn,String
vel,String
ch,String
pm] ->
                  (forall a. Read a => String -> String -> a
T.reads_exact_err String
"time" String
st
                  ,forall a. Read a => String -> String -> a
T.reads_exact_err String
"duration" String
du
                  ,String
msg
                  ,n -> m
cnv (forall a. Read a => String -> String -> a
T.reads_exact_err String
"note" String
mnn)
                  ,n -> m
cnv (forall a. Read a => String -> String -> a
T.reads_exact_err String
"velocity" String
vel)
                  ,forall a. Read a => String -> String -> a
T.reads_exact_err String
"channel" String
ch
                  ,(Char, Char) -> String -> Param
param_parse (Char
';',Char
'=') String
pm)
              [String]
_ -> forall {a}. String -> a
err String
"entry?"
    in case Maybe [String]
hdr of
         Just [String]
hdr' -> if [String]
hdr' forall a. Eq a => a -> a -> Bool
== [String]
csv_mndd_hdr then forall a b. (a -> b) -> [a] -> [b]
map forall {a} {b} {f}.
(Read a, Read b, Read f) =>
[String] -> (a, b, String, m, m, f, Param)
f Table String
dat else forall {a}. String -> a
err String
"header?"
         Maybe [String]
Nothing -> forall {a}. String -> a
err String
"no header?"

-- | Pars midi note/duration data from Csv table.
csv_mndd_parse :: (Read t,Real t,Read n,Real n) => T.Csv_Table String -> [Mndd t n]
csv_mndd_parse :: forall t n.
(Read t, Real t, Read n, Real n) =>
Csv_Table String -> [Mndd t n]
csv_mndd_parse = forall t n m.
(Read t, Real t, Read n, Real n) =>
(n -> m) -> Csv_Table String -> [Mndd t m]
csv_mndd_parse_f forall a. a -> a
id

-- | 'csv_mndd_parse' of 'load_csv'
csv_mndd_read :: (Read t,Real t,Read n,Real n) => FilePath -> IO [Mndd t n]
csv_mndd_read :: forall t n.
(Read t, Real t, Read n, Real n) =>
String -> IO [Mndd t n]
csv_mndd_read = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall t n.
(Read t, Real t, Read n, Real n) =>
Csv_Table String -> [Mndd t n]
csv_mndd_parse forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO (Csv_Table String)
load_csv

-- | Writer.
csv_mndd_write :: (Real t,Real n) => Int -> FilePath -> [Mndd t n] -> IO ()
csv_mndd_write :: forall t n.
(Real t, Real n) =>
Int -> String -> [Mndd t n] -> IO ()
csv_mndd_write Int
r_prec String
nm =
    let un_node :: (t, t, String, t, t, a, Param) -> [String]
un_node (t
st,t
du,String
msg,t
mnn,t
vel,a
ch,Param
pm) =
            [forall t. Real t => Int -> t -> String
T.real_pp Int
r_prec t
st,forall t. Real t => Int -> t -> String
T.real_pp Int
r_prec t
du,String
msg
            ,forall t. Real t => Int -> t -> String
data_value_pp Int
r_prec t
mnn,forall t. Real t => Int -> t -> String
data_value_pp Int
r_prec t
vel
            ,forall a. Show a => a -> String
show a
ch
            ,(Char, Char) -> Int -> Param -> String
param_pp (Char
';',Char
'=') Int
r_prec Param
pm]
        with_hdr :: b -> (Maybe [String], b)
with_hdr b
dat = (forall a. a -> Maybe a
Just [String]
csv_mndd_hdr,b
dat)
    in forall a.
(a -> String) -> Csv_Opt -> String -> Csv_Table a -> IO ()
T.csv_table_write forall a. a -> a
id Csv_Opt
T.def_csv_opt String
nm forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {b}. b -> (Maybe [String], b)
with_hdr forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map forall {t} {t} {t} {t} {a}.
(Real t, Real t, Real t, Real t, Show a) =>
(t, t, String, t, t, a, Param) -> [String]
un_node

-- * Mndd Seq forms

-- | Ignores non note messages.
mndd_to_wseq :: [Mndd t n] -> T.Wseq t (Event n)
mndd_to_wseq :: forall t n. [Mndd t n] -> Wseq t (Event n)
mndd_to_wseq =
    let mk_node :: (a, b, String, a, b, c, d) -> Maybe ((a, b), (a, b, c, d))
mk_node (a
st,b
du,String
msg,a
mnn,b
vel,c
ch,d
pm) =
            case String
msg of
              String
"note" -> forall a. a -> Maybe a
Just ((a
st,b
du),(a
mnn,b
vel,c
ch,d
pm))
              String
_ -> forall a. Maybe a
Nothing
    in forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe forall {a} {b} {a} {b} {c} {d}.
(a, b, String, a, b, c, d) -> Maybe ((a, b), (a, b, c, d))
mk_node

-- | 'Wseq' form of 'csv_mndd_read'.
csv_mndd_read_wseq :: (Read t,Real t,Read n,Real n) => FilePath -> IO (T.Wseq t (Event n))
csv_mndd_read_wseq :: forall t n.
(Read t, Real t, Read n, Real n) =>
String -> IO (Wseq t (Event n))
csv_mndd_read_wseq = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall t n. [Mndd t n] -> Wseq t (Event n)
mndd_to_wseq forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall t n.
(Read t, Real t, Read n, Real n) =>
String -> IO [Mndd t n]
csv_mndd_read

-- | 'Wseq' form of 'csv_mndd_write'.
csv_mndd_write_wseq :: (Real t,Real n) => Int -> FilePath -> T.Wseq t (Event n) -> IO ()
csv_mndd_write_wseq :: forall t n.
(Real t, Real n) =>
Int -> String -> Wseq t (Event n) -> IO ()
csv_mndd_write_wseq Int
r_prec String
nm =
    let f :: ((a, b), (d, e, f, g)) -> (a, b, String, d, e, f, g)
f ((a
st,b
du),(d
mnn,e
vel,f
ch,g
pm)) = (a
st,b
du,String
"note",d
mnn,e
vel,f
ch,g
pm)
    in forall t n.
(Real t, Real n) =>
Int -> String -> [Mndd t n] -> IO ()
csv_mndd_write Int
r_prec String
nm forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map forall {a} {b} {d} {e} {f} {g}.
((a, b), (d, e, f, g)) -> (a, b, String, d, e, f, g)
f

-- * Composite

-- | Parse either Mnd or Mndd data to Wseq, Csv type is decided by header.
csv_midi_parse_wseq_f :: (Read t,Real t,Read n,Real n,Num m, Eq m) => (n -> m) -> T.Csv_Table String -> T.Wseq t (Event m)
csv_midi_parse_wseq_f :: forall t n m.
(Read t, Real t, Read n, Real n, Num m, Eq m) =>
(n -> m) -> Csv_Table String -> Wseq t (Event m)
csv_midi_parse_wseq_f n -> m
cnv (Maybe [String]
hdr,Table String
dat) = do
  case Maybe [String]
hdr of
    Just [String]
hdr' -> if [String]
hdr' forall a. Eq a => a -> a -> Bool
== [String]
csv_mnd_hdr
                 then forall t n.
(Num t, Eq n) =>
Tseq t (Begin_End (Event n)) -> Wseq t (Event n)
midi_tseq_to_midi_wseq (forall n t. Num n => [Mnd t n] -> Tseq t (Begin_End (Event n))
mnd_to_tseq (forall t n m.
(Read t, Real t, Read n, Real n) =>
(n -> m) -> Csv_Table String -> [Mnd t m]
csv_mnd_parse_f n -> m
cnv (Maybe [String]
hdr,Table String
dat)))
                 else if [String]
hdr' forall a. Eq a => a -> a -> Bool
== [String]
csv_mndd_hdr
                      then forall t n. [Mndd t n] -> Wseq t (Event n)
mndd_to_wseq (forall t n m.
(Read t, Real t, Read n, Real n) =>
(n -> m) -> Csv_Table String -> [Mndd t m]
csv_mndd_parse_f n -> m
cnv (Maybe [String]
hdr,Table String
dat))
                      else forall a. HasCallStack => String -> a
error String
"csv_midi_read_wseq: not Mnd or Mndd"
    Maybe [String]
_ -> forall a. HasCallStack => String -> a
error String
"csv_midi_read_wseq: header?"

csv_midi_parse_wseq :: (Read t,Real t,Read n,Real n) => T.Csv_Table String -> T.Wseq t (Event n)
csv_midi_parse_wseq :: forall t n.
(Read t, Real t, Read n, Real n) =>
Csv_Table String -> Wseq t (Event n)
csv_midi_parse_wseq = forall t n m.
(Read t, Real t, Read n, Real n, Num m, Eq m) =>
(n -> m) -> Csv_Table String -> Wseq t (Event m)
csv_midi_parse_wseq_f forall a. a -> a
id

csv_midi_read_wseq :: (Read t,Real t,Read n,Real n) => FilePath -> IO (T.Wseq t (Event n))
csv_midi_read_wseq :: forall t n.
(Read t, Real t, Read n, Real n) =>
String -> IO (Wseq t (Event n))
csv_midi_read_wseq = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall t n.
(Read t, Real t, Read n, Real n) =>
Csv_Table String -> Wseq t (Event n)
csv_midi_parse_wseq forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO (Csv_Table String)
load_csv