\begin{code}
module Music.Analysis.MusicXML2Haskore where
import Music.Analysis.PF
import qualified Haskore ()
import qualified Haskore.Music as HMusic
import qualified Haskore.Basic.Pitch as HPitch
import qualified Haskore.Melody as HMelody
import qualified Haskore.Music.GeneralMIDI as GeneralMIDI
import qualified Medium.Controlled.List as Medium
import qualified Haskore.Interface.MIDI.Render as Render
import Data.List
import Data.Maybe
import Numeric.NonNegative.Wrapper as NonNeg
import qualified Music.Analysis.MusicXML as IMusicXML
import qualified Music.Analysis.MusicXML.Level5 as Layer5
import qualified Music.Analysis.MusicXML.Level1 as Layer1
import qualified Text.XML.MusicXML as MusicXML
import qualified Text.XML.MusicXML.Partwise as Partwise
import System.Info
import System.Cmd
import System.Exit
import Prelude
\end{code}
\begin{code}
from_Score_Partwise :: MusicXML.Score_Partwise -> MusicXML.Score_Partwise
from_Score_Partwise = (id >< (id >< fmap from_Part))
from_Part :: Partwise.Part -> Partwise.Part
from_Part = (id >< fmap from_Measure)
from_Measure :: Partwise.Measure -> Partwise.Measure
from_Measure = (id >< fmap from_Music_Data)
from_Music_Data :: MusicXML.Music_Data_ -> MusicXML.Music_Data_
from_Music_Data (MusicXML.Music_Data_1 x) =
MusicXML.Music_Data_1 (from_Note x)
from_Music_Data (MusicXML.Music_Data_2 x) = MusicXML.Music_Data_2 x
from_Music_Data (MusicXML.Music_Data_3 x) = MusicXML.Music_Data_3 x
from_Music_Data (MusicXML.Music_Data_4 x) = MusicXML.Music_Data_4 x
from_Music_Data (MusicXML.Music_Data_5 x) = MusicXML.Music_Data_5 x
from_Music_Data (MusicXML.Music_Data_6 x) = MusicXML.Music_Data_6 x
from_Music_Data (MusicXML.Music_Data_7 x) = MusicXML.Music_Data_7 x
from_Music_Data (MusicXML.Music_Data_8 x) = MusicXML.Music_Data_8 x
from_Music_Data (MusicXML.Music_Data_9 x) = MusicXML.Music_Data_9 x
from_Music_Data (MusicXML.Music_Data_10 x) = MusicXML.Music_Data_10 x
from_Music_Data (MusicXML.Music_Data_11 x) = MusicXML.Music_Data_11 x
from_Music_Data (MusicXML.Music_Data_12 x) = MusicXML.Music_Data_12 x
from_Music_Data (MusicXML.Music_Data_13 x) = MusicXML.Music_Data_13 x
from_Note :: MusicXML.Note -> MusicXML.Note
from_Note = id
\end{code}
\begin{code}
group_Part :: Partwise.Part -> [[[[MusicXML.Note]]]]
group_Part =
fmap (concat . group_Measure) . p2
group_Measure :: Partwise.Measure -> [[[[MusicXML.Note]]]]
group_Measure =
(fmap . fmap) (groupBy group_Instrument . sortBy cmp_Instrument) .
fmap (groupBy group_Staff . sortBy cmp_Staff) .
groupBy group_Voice . sortBy cmp_Voice .
toNote . p2
toNote :: [MusicXML.Music_Data_] -> [MusicXML.Note]
toNote = catMaybes . fmap f
where f (MusicXML.Music_Data_1 x) = return x
f _ = fail []
group_Music_Data_ :: (MusicXML.Note -> MusicXML.Note -> Bool) ->
MusicXML.Music_Data_ -> MusicXML.Music_Data_ -> Bool
group_Music_Data_ p (MusicXML.Music_Data_1 x) (MusicXML.Music_Data_1 y) = p x y
group_Music_Data_ _ _ _ = False
group_Instrument :: MusicXML.Note -> MusicXML.Note -> Bool
group_Instrument = (\ (_,(_,x2,_,_,_,_,_,_,_,_,_,_,_))
(_,(_,y2,_,_,_,_,_,_,_,_,_,_,_)) -> x2 == y2)
group_Voice :: MusicXML.Note -> MusicXML.Note -> Bool
group_Voice = (\ (_,(_,_,(_,_,x3),_,_,_,_,_,_,_,_,_,_))
(_,(_,_,(_,_,y3),_,_,_,_,_,_,_,_,_,_)) -> x3 == y3)
group_Staff :: MusicXML.Note -> MusicXML.Note -> Bool
group_Staff = (\ (_,(_,_,_,_,_,_,_,_,_,x10,_,_,_))
(_,(_,_,_,_,_,_,_,_,_,y10,_,_,_)) -> x10 == y10)
cmp_Instrument :: MusicXML.Note -> MusicXML.Note -> Ordering
cmp_Instrument = (\ (_,(_,x2,_,_,_,_,_,_,_,_,_,_,_))
(_,(_,y2,_,_,_,_,_,_,_,_,_,_,_)) -> x2 `compare` y2)
cmp_Voice :: MusicXML.Note -> MusicXML.Note -> Ordering
cmp_Voice = (\ (_,(_,_,(_,_,x3),_,_,_,_,_,_,_,_,_,_))
(_,(_,_,(_,_,y3),_,_,_,_,_,_,_,_,_,_)) -> x3 `compare` y3)
cmp_Staff :: MusicXML.Note -> MusicXML.Note -> Ordering
cmp_Staff = (\ (_,(_,_,_,_,_,_,_,_,_,x10,_,_,_))
(_,(_,_,_,_,_,_,_,_,_,y10,_,_,_)) -> x10 `compare` y10)
get_Instrument :: MusicXML.Note -> Maybe MusicXML.Instrument
get_Instrument (_,(_,x2,_,_,_,_,_,_,_,_,_,_,_)) = x2
get_Voice :: MusicXML.Note -> Maybe MusicXML.Voice
get_Voice (_,(_,_,(_,_,x3),_,_,_,_,_,_,_,_,_,_)) = x3
get_Staff :: MusicXML.Note -> Maybe MusicXML.Staff
get_Staff (_,(_,_,_,_,_,_,_,_,_,x10,_,_,_)) = x10
\end{code}
\begin{code}
group_Measure' :: Partwise.Measure ->
[(Maybe MusicXML.Instrument,
[(Maybe MusicXML.Staff,
[(Maybe MusicXML.Voice, [MusicXML.Note])])])]
group_Measure' =
map (id >< map (id >< map (split (headM . map get_Voice) id))) .
map (id >< map (split ((headM.headM) . (map.map) get_Staff) id)) .
map (split ((headM.headM.headM) . (map.map.map) get_Instrument) id) .
group_Measure
headM :: Monad m => [m a] -> m a
headM [] = fail "empty list"
headM (x:_) = x
\end{code}
\begin{code}
toMedium_ :: [[[[Medium.T control a]]]] -> Medium.T control a
toMedium_ =
Medium.parallel .
((map) Medium.parallel) .
((map . map) Medium.parallel) .
((map . map . map) Medium.serial)
toMedium :: [[[[a]]]] -> Medium.T control a
toMedium =
Medium.parallel .
((map) Medium.parallel) .
((map . map) Medium.parallel) .
((map . map . map) Medium.serial) .
(map . map . map . map) Medium.prim
toMedium' :: [(Maybe MusicXML.Instrument,
[(Maybe MusicXML.Staff,
[(Maybe MusicXML.Voice, [MusicXML.Note])])])] ->
Medium.T ControlID MusicXML.Note
toMedium' =
Medium.parallel .
(map (uncurry Medium.Control .
(Control_Instrument >< Medium.parallel))) .
(map (id >< map (uncurry Medium.Control .
(Control_Staff >< Medium.parallel)))) .
(map (id >< map (id >< map (uncurry Medium.Control .
(Control_Voice >< Medium.serial))))) .
(map (id >< map (id >< map (id >< map Medium.prim)))) .
id
data ControlID = Control_Instrument (Maybe MusicXML.Instrument)
| Control_Staff (Maybe MusicXML.Staff)
| Control_Voice (Maybe MusicXML.Voice)
deriving (Eq, Show)
\end{code}
\begin{code}
abst_Step :: MusicXML.Step -> Maybe Layer1.Step
abst_Step = IMusicXML.abst_Step
abst_Octave :: MusicXML.Octave -> Layer1.Octave
abst_Octave = IMusicXML.abst_Octave
abst_Alter :: MusicXML.Alter -> Maybe Layer1.Alter
abst_Alter = IMusicXML.abst_Alter
toClass :: Layer1.Step -> Maybe Layer1.Alter -> HPitch.Class
toClass step Nothing = toEnum (3*(fromEnum step) + 1)
toClass step (Just alter) =
toEnum (3*(fromEnum step) + 1 + (truncate ((3/2)*alter)))
abst_Pitch :: MusicXML.Pitch -> (Layer1.Octave, HPitch.Class)
abst_Pitch =
swap . (uncurry toClass >< id) . unflatl . IMusicXML.abst_Pitch
abst_Full_Note_ :: MusicXML.Full_Note_ -> Maybe HPitch.T
abst_Full_Note_ (MusicXML.Full_Note_1 x) = return (abst_Pitch x)
abst_Full_Note_ _ = fail []
abst_Full_Note :: MusicXML.Full_Note -> Maybe HPitch.T
abst_Full_Note = abst_Full_Note_ . p2
abst_Note_ :: MusicXML.Note_ -> (Maybe HPitch.T, Maybe Layer5.Duration)
abst_Note_ (MusicXML.Note_1 _) = (Nothing, Nothing)
abst_Note_ (MusicXML.Note_2 x) =
((abst_Full_Note >< Just . abst_Duration) . p2 . unflatr) x
abst_Note_ (MusicXML.Note_3 x) =
((abst_Full_Note >< Just . abst_Duration) . p1 . unflatl) x
abst_Duration :: MusicXML.Duration -> Layer5.Duration
abst_Duration = IMusicXML.abst_Duration
toDur :: Layer5.Duration -> HMusic.Dur
toDur n = NonNeg.fromNumber (fromIntegral n)
abst_Note :: MusicXML.Note -> HMusic.T HPitch.T
abst_Note (_,(a,_,_,_,_,_,_,_,_,_,_,_,_)) =
case abst_Note_ a of
(Just a1, Just a2) -> HMusic.atom (toDur a2) (Just a1)
(Nothing, Just a2) -> HMusic.rest (toDur a2)
(_,Nothing) -> HMusic.rest 0
abst_Note' :: MusicXML.Note -> HMelody.T MusicXML.Note
abst_Note' n@(_,(a,_,_,_,_,_,_,_,_,_,_,_,_)) =
case abst_Note_ a of
(Just a1, Just a2) -> HMusic.atom (toDur a2) (Just (HMelody.Note n a1))
(Nothing, Just a2) -> HMusic.rest (toDur a2)
(_,Nothing) -> HMusic.rest 0
\end{code}
\begin{code}
measure2haskore :: Partwise.Measure -> HMelody.T MusicXML.Note
measure2haskore = toMedium_ . (map.map.map.map) abst_Note' . group_Measure
part2haskore :: Partwise.Part -> HMelody.T MusicXML.Note
part2haskore = Medium.Serial . map measure2haskore . p2
partwise2haskore :: Partwise.Score_Partwise -> HMelody.T MusicXML.Note
partwise2haskore = Medium.Parallel . fmap part2haskore . p2 . p2
toMidi :: MusicXML.MusicXMLDoc -> GeneralMIDI.T
toMidi (MusicXML.Score (MusicXML.Partwise music)) =
(GeneralMIDI.fromMelodyNullAttr GeneralMIDI.AcousticGrandPiano .
fmap fun . partwise2haskore) music
where fun (HMusic.Atom x Nothing) = HMusic.Atom x Nothing
fun (HMusic.Atom x (Just (HMelody.Note _ y))) =
HMusic.Atom x (Just (HMelody.Note () y))
toMidi (_) =
(GeneralMIDI.fromMelodyNullAttr GeneralMIDI.AcousticGrandPiano .
fmap fun . Medium.Parallel) []
where fun (HMusic.Atom x Nothing) = HMusic.Atom x Nothing
fun (HMusic.Atom x (Just (HMelody.Note _ y))) =
HMusic.Atom x (Just (HMelody.Note () y))
saveMidi :: FilePath -> GeneralMIDI.T -> IO ()
saveMidi filepath = Render.fileFromGeneralMIDIMusic filepath
playMidi :: FilePath -> GeneralMIDI.T -> IO ExitCode
playMidi filepath music =
Render.fileFromGeneralMIDIMusic filepath music >> playGeneric filepath
playGeneric :: FilePath -> IO ExitCode
playGeneric filepath =
case System.Info.os of
"mingw32" -> rawSystem "mplay32" [filepath]
"linux" -> rawSystem "playmidi" ["-rf", filepath]
_ -> rawSystem "timidity" ["-B8,9", filepath]
\end{code}
\begin{nocode}
-- > play cmd opts m =
-- > do fileFromGeneralMIDIMusic fileName m
-- > rawSystem cmd (opts ++ [fileName])
-- > return ()
-- GeneralMIDI.fromMelodyNullAttr GeneralMIDI.AcousticGrandPiano .
-- fmap fun . partwise2haskore
-- where fun (HMusic.Atom x Nothing) = HMusic.Atom x Nothing
-- fun (HMusic.Atom x (Just (HMelody.Note _ y))) =
-- HMusic.Atom x (Just (HMelody.Note () y))
--fromStdMelody instr = HMusic.mapNote (noteFromStdMelodyNote instr)
-- > noteFromStdMelodyNote :: instr -> StdMelody.Note -> Note drum instr
--noteFromAttrs nas = HRhythmic.Note (Accessor.get StdMelody.velocity1 nas)
--noteFromStdMelodyNote instr (HMelody.Note nas p) = noteFromAttrs nas (HRhythmic.Tone instr p)
\end{nocode}
\begin{nocode}
-- || input Music from Haskore
input :: Music -> Motive MultiInstrumentNode
input (Note p d _) = mkMotive settings [[(((inputPitch p,inputDur d),1),[])]]
input (Rest d) = mkMotive settings [[(((Nothing, inputDur d), 1),[])]]
input (m1 :+: m2) = seq (input m1) (input m2)
input (m1 :=: m2) = par (input m1) (input m2)
input (Instr _ m) = input m
input (Player _ m) = input m
input _ = mkMotive settings []
\end{nocode}
\begin{nocode}
-- ||
inputPitch :: Pitch -> MelodicNode
inputPitch = (const (Just (0,0))) . p1
-- ||
inputDur :: Dur -> RhythmNode
inputDur = const (1,0)
\end{nocode}
\begin{nocode}
-- |
par :: Motive a -> Motive a -> Motive a
par m1 m2 =
let (s1, l1) = fromMotive m1
(s2, l2) = fromMotive m2
in toMotive ((s1`union`s2), (l1 ++ l2))
-- | BUG
seq :: Motive a -> Motive a -> Motive a
seq m1 m2 =
let (s1, l1) = fromMotive m1
(s2, l2) = fromMotive m2
in toMotive ((s1`union`s2), (l1 ++ l2))
\end{nocode}
\begin{nocode}
--output :: Motive MultiInstrumentNode -> Music
--output = outputInstrument
outputInstrument :: Motive MultiInstrumentNode -> [Motive MultiInstrumentNode]
outputInstrument =
mapL (toMotive . outputVoice) .
splitMotiveList
-- uncurry
-- (maybe "Piano" id . getText "Instrument" >< id) .
-- cataMotive [] (\s -> uncurry (:) . (outputVoice >< id))
-- fromMotive
--outputVoice :: Motive MultiVoiceNode -> Motive MultiVoiceNode
outputVoice = cataMotive [] (\s -> uncurry (:) . (id >< id))
--outputZip :: Motive VoiceZipNode -> Motive VoiceZipNode
outputZip = cataMotive [] (\s -> uncurry (:))
\end{nocode}
\begin{nocode}
inRest :: RhythmNode -> Music
inRest = Rest . uncurry (%) . (toInteger >< toInteger)
inNote :: VoiceZipNode -> Music
inNote = either (f . p2) (uncurry g) . grd (isNothing . p1)
where f = (Rest . uncurry (%) . (toInteger >< toInteger))
g p d = Note ((const (C,0)) p) ((uncurry (%) . (toInteger >< toInteger)) d) []
\end{nocode}