module ZMidi.Core.Pretty.Ascii
(
putAscii
, printAscii
) where
import ZMidi.Core.Datatypes
import ZMidi.Core.Internal.SimpleFormat
import ZMidi.Core.Pretty.Internal
import ZMidi.Core.Pretty.Interp
#ifndef MIN_VERSION_GLASGOW_HASKELL
import Data.Monoid
#endif
import Data.Word
putAscii :: MidiFile -> IO ()
putAscii = mapM_ putStrLn . printAscii
printAscii :: MidiFile -> [String]
printAscii (MidiFile hdr tracks) = execTable body_columns $ do
tellBreak
tellMidiHeader hdr
tellBreak
mapM_ (\t -> columnHeaders >> tellBreak >> tellTrack t >> tellBlank )
tracks
tellTrack :: MidiTrack -> Table ()
tellTrack (MidiTrack xs) = nextTrack >> mapM_ message xs
body_columns :: ColumnSpecs
body_columns =
ColumnSpecs ' ' [ PadR 3
, PadR 15
, PadR 7
, PadL 7
, PadL 11
, PadL 13
, PadL 9
]
message :: MidiMessage -> Table ()
message (delta,evt) = do
incrDelta $ fromIntegral delta
tellRow $ \track_num acctime -> [ integral track_num
, descEvent evt
, eventNoteName evt
, eventKeyNumber evt
, integral delta
, integral acctime
, eventVelocity evt
]
columnHeaders :: Table ()
columnHeaders = tellRow $ \_ _ ->
map text [ "Trk"
, "Event Type"
, "Note"
, "Key no"
, "Delta Time"
, "Elapsed Time"
, "Velocity"
]
descEvent :: MidiEvent -> WString
descEvent (VoiceEvent rs e) = descVoiceEvent rs e
descEvent (MetaEvent e) = descMetaEvent e
descEvent _ = mempty
descVoiceEvent :: MidiRunningStatus -> MidiVoiceEvent -> WString
descVoiceEvent _ (Controller {}) = text "Controller"
descVoiceEvent _ (ProgramChange {}) = text "Program change"
descVoiceEvent _ (NoteOff {}) = text "Note off"
descVoiceEvent rs (NoteOn _ _ v)
| rs == RS_ON && v == 0 = text "Note on*"
| otherwise = text "Note on"
descVoiceEvent _ (NoteAftertouch {}) = text "Note aftertouch"
descVoiceEvent _ (ChanAftertouch {}) = text "Channel aftertouch"
descVoiceEvent _ (PitchBend {}) = text "Pitch bend"
descMetaEvent :: MidiMetaEvent -> WString
descMetaEvent (TextEvent ty _) = text $ textType ty
descMetaEvent (SequenceNumber {}) = text "Sequence number"
descMetaEvent (ChannelPrefix {}) = text "Channel prefix"
descMetaEvent (MidiPort {}) = text "Midi port"
descMetaEvent (EndOfTrack) = text "End of track"
descMetaEvent (SetTempo {}) = text "Set tempo"
descMetaEvent (SMPTEOffset {}) = text "SMTPE offest"
descMetaEvent (TimeSignature {}) = text "Time signature"
descMetaEvent (KeySignature {}) = text "Key signature"
descMetaEvent (SSME {}) = text "SSME"
descMetaEvent (MetaOther {}) = text "Meta other"
eventNoteName :: MidiEvent -> WString
eventNoteName (VoiceEvent _ e) = voiceEventNoteName e
eventNoteName _ = mempty
noteName :: Word8 -> WString
noteName = text . simpleNoteName . fromIntegral
voiceEventNoteName :: MidiVoiceEvent -> WString
voiceEventNoteName (Controller _ n _) = noteName n
voiceEventNoteName (ProgramChange _ n) = noteName n
voiceEventNoteName (NoteOff _ n _) = noteName n
voiceEventNoteName (NoteOn _ n _) = noteName n
voiceEventNoteName (NoteAftertouch _ n _) = noteName n
voiceEventNoteName (ChanAftertouch _ _) = mempty
voiceEventNoteName (PitchBend _ _) = mempty
eventKeyNumber :: MidiEvent -> WString
eventKeyNumber (VoiceEvent _ e) = voiceEventKeyNumber e
eventKeyNumber _ = mempty
voiceEventKeyNumber :: MidiVoiceEvent -> WString
voiceEventKeyNumber (Controller _ n _) = integral n
voiceEventKeyNumber (ProgramChange _ n) = integral n
voiceEventKeyNumber (NoteOff _ n _) = integral n
voiceEventKeyNumber (NoteOn _ n _) = integral n
voiceEventKeyNumber (NoteAftertouch _ n _) = integral n
voiceEventKeyNumber (ChanAftertouch _ _) = mempty
voiceEventKeyNumber (PitchBend _ _) = mempty
eventVelocity :: MidiEvent -> WString
eventVelocity (VoiceEvent _ e) = voiceEventVelocity e
eventVelocity _ = mempty
voiceEventVelocity :: MidiVoiceEvent -> WString
voiceEventVelocity (Controller _ _ v) = integral v
voiceEventVelocity (ProgramChange _ _) = mempty
voiceEventVelocity (NoteOff _ _ v) = integral v
voiceEventVelocity (NoteOn _ _ v) = integral v
voiceEventVelocity (NoteAftertouch _ _ v) = integral v
voiceEventVelocity (ChanAftertouch _ v) = integral v
voiceEventVelocity (PitchBend _ v) = integral v