Chapter 22
Download
1 / 8

Chapter 22 - PowerPoint PPT Presentation


  • 228 Views
  • Updated On :

Chapter 22. From Performance to MIDI. 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.

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about 'Chapter 22' - ivanbritt


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
Chapter 22 l.jpg

Chapter 22

From Performance to MIDI


Motivation l.jpg
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.


Our goal l.jpg
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”.


Midifile data type l.jpg
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 ]


Midi events l.jpg
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


Performtomidi l.jpg
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).


Performtomevs l.jpg
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'


Mkmevents l.jpg
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)


ad