MidiFile outputMidiFile :: String -> MidiFile -> IO ()  “MidiFile” and “outputMidiFile” are imported from Haskore. Our main job is to define “performToMidi”."> MidiFile outputMidiFile :: String -> MidiFile -> IO ()  “MidiFile” and “outputMidiFile” are imported from Haskore. Our main job is to define “performToMidi”.">

Presentation is loading. Please wait.

Presentation is loading. Please wait.

Chapter 22 From Performance to MIDI. Motivation  Abstractly, an MDL program denotes a Performance.  But a Performance is just a Haskell data structure.

Similar presentations


Presentation on theme: "Chapter 22 From Performance to MIDI. Motivation  Abstractly, an MDL program denotes a Performance.  But a Performance is just a Haskell data structure."— Presentation transcript:

1 Chapter 22 From Performance to MIDI

2 Motivation  Abstractly, an MDL program denotes a Performance.  But a Performance is just a Haskell data structure – we can analyze it, but we cannot hear it!  To remedy this, we will convert a Performance into a MIDI File.  MIDI (Musical Instrument Digital Interface) is a standard protocol for describing electronic music.  The MIDI file format is part of this standard, and all consumer PC’s are capable of playing them through the PC’s sound card.  In addition, General MIDI standardizes instrument and percussion names as used in MDL.

3 Our Goal  We need to define a function (called “test” in text): musicToMidi :: Music -> IO () musicToMidi = outputMidiFile "test.mid“. performToMidi. perform defCon  “perform” was defined in the previous chapter, and “defCon” is just the default Context.  So additionally we need: performToMidi :: Performance -> MidiFile outputMidiFile :: String -> MidiFile -> IO ()  “MidiFile” and “outputMidiFile” are imported from Haskore. Our main job is to define “performToMidi”.

4 MidiFile Data Type  The MidiFile data type (imported from Haskore) captures the essence of a Midi file: data MidiFile = MidiFile MFType Division [Track] deriving (Show, Eq) type MFType = Int type Track = [MEvent] data Division = Ticks Int | SMPTE Int Int deriving (Show,Eq) data MEvent= MidiEvent ElapsedTime MidiEvent | MetaEvent ElapsedTime MetaEvent | NoEvent deriving (Show,Eq) type ElapsedTime = Int [ see text for details ]

5 MIDI Events  MIDI events are like MDL events, except that there are events for both start and end of a note: data MidiEvent = | NoteOff MidiChannel MPitch Velocity | NoteOn MidiChannel MPitch Velocity | ProgChange MidiChannel ProgNum |... deriving (Show, Eq) type MPitch= Int;type Velocity = Int type ProgNum= Int;type MidiChannel = Int data MetaEvent = SetTempo MTempo |... deriving (Show, Eq) type MTempo = Int

6 performToMidi  To convert a Performance into a MidiFile value: performToMidi :: Performance -> MidiFile performToMidi pf = MidiFile mfType (Ticks division) (map performToMEvs (splitByInst pf)) mfType = 1:: Int division = 96:: Int  This leaves two functions: splitByInst :: Performance -> [(MidiChannel,ProgNum,Performance)] performToMEvs :: (MidiChannel,ProgNum,Performance) -> [MEvent]  In a Type 1 MIDI file, each instrument is associated with a separate track. splitByInst splits the Performance to achieve this (see text for details).

7 performToMEvs performToMEvs :: (MidiChannel,ProgNum,Performance) -> [MEvent] performToMEvs (ch,pn,perf) = let setupInst= MidiEvent 0 (ProgChange ch pn) setTempo= MetaEvent 0 (SetTempo tempo) loop []= [] loop (e:es)= let (mev1,mev2) = mkMEvents ch e in mev1 : insertMEvent mev2 (loop es) in setupInst : setTempo : loop perf tempo = 500000 :: Int-- number of microsecs in one beat insertMEvent :: MEvent -> [MEvent] -> [MEvent] insertMEvent ev1 [] = [ev1] insertMEvent ev1@(MidiEvent t1 _) evs@(ev2@(MidiEvent t2 _) : evs') = if t1 <= t2 then ev1 : evs else ev2 : insertMEvent ev1 evs'

8 mkMEvents  Finally, we convert individual notes: mkMEvents :: MidiChannel -> Event -> (MEvent,MEvent) mkMEvents mChan (Event { eTime = t, ePitch = p, eDur = d }) = ( MidiEvent (toDelta t) (NoteOn mChan p 127), MidiEvent (toDelta (t+d)) (NoteOff mChan p 127) ) toDelta t = round (t * 4.0 * intToFloat division)


Download ppt "Chapter 22 From Performance to MIDI. Motivation  Abstractly, an MDL program denotes a Performance.  But a Performance is just a Haskell data structure."

Similar presentations


Ads by Google