module Music.Theory.Array.CSV.Midi where
import Data.Function
import Data.Maybe
import qualified Music.Theory.Array.CSV as T
import qualified Music.Theory.Time.Seq as T
reads_exact :: Read a => String -> Maybe a
reads_exact s =
case reads s of
[(r,"")] -> Just r
_ -> Nothing
reads_err :: Read a => String -> a
reads_err str = fromMaybe (error ("could not read: " ++ str)) (reads_exact str)
csv_midi_note_data_hdr :: [String]
csv_midi_note_data_hdr = ["time","on/off","note","velocity"]
csv_midi_note_data_read' :: (Read t,Real t,Read n,Real n) => (m,m) -> FilePath -> IO [(t,Either m String,n,n)]
csv_midi_note_data_read' (m_on,m_off) =
let err x = error ("csv_midi_note_data_read: " ++ x)
read_md x = case x of
"on" -> Left m_on
"off" -> Left m_off
_ -> Right x
f m =
case m of
[st,md,mnn,amp] -> (reads_err st,read_md md,reads_err mnn,reads_err amp)
_ -> err "entry?"
g (hdr,dat) = case hdr of
Just hdr' -> if hdr' == csv_midi_note_data_hdr then dat else err "header?"
Nothing -> err "no header?"
in fmap (map f . g) . T.csv_table_read (True,',',False,T.CSV_No_Align) id
csv_midi_note_data_read :: (Read t,Real t,Read n,Real n) => (m,m) -> FilePath -> IO [(t,m,n,n)]
csv_midi_note_data_read m =
let f (t,p,q,r) = (t,either id (error "not on/off") p,q,r)
in fmap (map f) . csv_midi_note_data_read' m
midi_tseq_read :: (Read t,Real t,Read n,Real n) => FilePath -> IO (T.Tseq t (T.On_Off (n,n)))
midi_tseq_read =
let mk_node (st,md,mnn,amp) = if md
then (st,T.On (mnn,amp))
else (st,T.Off (mnn,0))
in fmap (map mk_node) . csv_midi_note_data_read (True,False)
midi_tseq_to_midi_wseq :: (Num t,Eq n) => T.Tseq t (T.On_Off (n,n)) -> T.Wseq t (n,n)
midi_tseq_to_midi_wseq = T.tseq_on_off_to_wseq ((==) `on` fst)
midi_wseq_to_midi_tseq :: (Num t,Ord t) => T.Wseq t (n,n) -> T.Tseq t (T.On_Off (n,n))
midi_wseq_to_midi_tseq = T.wseq_on_off
csv_midi_note_data_write :: (Eq m,Show t,Real t,Show n,Real n) => (m,m) -> FilePath -> [(t,m,n,n)] -> IO ()
csv_midi_note_data_write (m_on,m_off) nm =
let show_md md = if md == m_on
then "on" else if md == m_off
then "off"
else error "csv_midi_note_data_write"
un_node (st,md,mnn,amp) = [show st,show_md md,show mnn,show amp]
with_hdr dat = (Just csv_midi_note_data_hdr,dat)
in T.csv_table_write id T.def_csv_opt nm . with_hdr . map un_node
midi_tseq_write :: (Show t,Real t,Show n,Real n) => FilePath -> T.Tseq t (T.On_Off (n,n)) -> IO ()
midi_tseq_write nm sq =
let f (t,e) = case e of
T.On (n,v) -> (t,True,n,v)
T.Off (n,v) -> (t,False,n,v)
sq' = map f sq
in csv_midi_note_data_write (True,False) nm sq'