Lecture - PowerPoint PPT Presentation

About This Presentation
Title:

Lecture

Description:

... given a beats per minute setting and a duration for one beat (quarter note, half ... Division = 96. This means 96 ticks per quarter note. Track - [ Mevent] ... – PowerPoint PPT presentation

Number of Views:26
Avg rating:3.0/5.0
Slides: 28
Provided by: timsh3
Learn more at: http://web.cecs.pdx.edu
Category:
Tags: lecture

less

Transcript and Presenter's Notes

Title: Lecture


1
Lecture 19, Dec. 6, 2004
  • Todays Topics
  • Interpreting Music
  • Performance
  • MidiFile
  • Read
  • Chapters 21 - Interpreting Functional Music
  • Chapter 22 From Performance to Midi

2
Haskore
  • Haskore is a Haskell library for constructing
    digital music
  • The end result is a MIDI-file
  • Todays lecture
  • translating the Music datatype into a MIDI file

Haskell
Haskore
Haskore Abstract High Level Implementation indepe
ndent
MIDI low level bit based implementation standard
presentation
The point of todays lecture
3
Musical notation
cScale line c 4 qn, d 4 qn, e 4 qn,
f 4 qn, g 4 qn, a 4 qn, b 4 qn, c 5 qn
Algorithm
Note (C,4) (1 4) (Note (D,4) (1 4)
(Note (E,4) (1 4) (Note
(F,4) (1 4) (Note (G,4) (1 4)
(Note (A,4) (1 4)
(Note (B,4) (1 4)
(Note (C,5) (1 4)
(Rest (0 1)))))))))
Music algebraic datatype
4
Need a Shape transformation
  • Algebraic datatype is tree-like
  • MIDI-file is linear in shape
  • Need a flattening transformation

5
3 step process
  • Translate Music data type to Performance data
    type
  • this step begins the flattening process
  • It uses simpler notion of time than the
    midi-standard
  • Its purely functional (no actions)
  • Translate Performance data type to MidiFile data
    type
  • Introduces the MIDI notion of events.
  • Each note, rest etc. translates to two
    midi-events,
  • a start event
  • a stop event
  • Write MidiFile data type to a real MIDI format
    file
  • Lots of messy details. But luckily this is
    handled by the Haskell MIDI library.
  • First place that non-pure actions are introduced.

6
Performance data type
  • type Performance Event
  • data Event
  • Event eTime Time, -- start time
  • eInst IName, -- instrument
  • ePitch AbsPitch, -- pitch or note
  • eDur DurT -- duration
  • deriving (Eq,Ord,Show)
  • type Time Float
  • type DurT Float

7
Haskell record syntax
  • data Event Event eTime Time,
  • eInst IName,
  • ePitch AbsPitch,
  • eDur DurT
  • Normal constructor notation
  • (Event start-time instrument pitch duration)
  • Also introduces selector functions
  • eTime Event -gt Time
  • eInst Event -gt Iname
  • ePitch Event -gt AbsPitch
  • eDur Event -gt DurT
  • And an update notation
  • x eTime y Event y (eInst x) (ePitch x)
    (eDur x)
  • where x has shape (Event a b c d)

8
perform Context -gt Music -gt Performance
  • The function perform translates a Music value
    into a Performance in some Context
  • A Context contains
  • time to begin the performance
  • the proper musical key to play the performance
  • the tempo (or speed) to play the performance
  • the instrument to use (unless one is explicitly
    given)
  • data Context Context cTime Time, cInst
    IName,
  • cDur DurT, cKey
    Key
  • deriving Show
  • type Key AbsPitch
  • metro computes the time for one whole note, given
    a beats per minute setting and a duration for one
    beat (quarter note, half note etc).
  • metro Float -gt Dur -gt DurT
  • metro setting dur 60 / (setting ratioToFloat
    dur)

9
Simple Perform
  • perform c_at_(Context t i dt k) m
  • case m of
  • Note p d -gt let dur ratioToFloat d dt
  • in Event t i (transpose p k i)
    dur
  • Rest d -gt
  • m1 m2 -gt
  • perform c m1
  • perform (c cTime t ratioToFloat (dur
    m1) dt) m2
  • m1 m2 -gt merge (perform c m1) (perform c
    m2)
  • Tempo a m -gt
  • perform (c cDur dt / ratioToFloat a ) m
  • Trans p m -gt perform (c cKey k p ) m
  • Instr nm m -gt perform (c cInst nm ) m
  • where transpose p k Percussion absPitch p
  • transpose p k _ absPitch p k

Quadratic running time
10
Consider a Music Tree like this
  • A tree, skewed to the left, will be very
    expensive to translate
  • m1 m2 -gt
  • perform c m1
  • perform
  • (c cTime ...(dur m1)...) m2
  • Solution compute the translation and the
    duration of the Music-tree simultaneously.
  • Have perform return a pair
  • perform Context -gt Music -gt (Performance,DurT)

11
Efficient perform
  • perform Context -gt Music -gt Performance
  • perform c m fst (perf c m)
  • perf Context -gt Music -gt (Performance, DurT)
  • perf c_at_(Context t i dt k) m
  • case m of
  • Note p d -gt let dur ratioToFloat d dt
  • in (Event t i (transpose p k
    i) dur, dur)
  • Rest d -gt (, ratioToFloat d dt)
  • m1 m2 -gt let (pf1,d1) perf c m1
  • (pf2,d2) perf (c cTime
    td1 ) m2
  • in (pf1pf2, d1d2)
  • m1 m2 -gt let (pf1,d1) perf c m1
  • (pf2,d2) perf c m2
  • in (merge pf1 pf2, max d1 d2)
  • Tempo a m -gt perf (c cDur dt /
    ratioToFloat a ) m
  • Trans p m -gt perf (c cKey k p ) m
  • Instr nm m -gt perf (c cInst nm ) m
  • where transpose p k Percussion absPitch p

Note how the context changes in recursive calls
12
merge
  • Consider the case for parallel composition
    (chords etc.)
  • m1 m2 -gt let (pf1,d1) perf c m1
  • (pf2,d2) perf c m2
  • in (merge pf1 pf2, max d1 d2)
  • merge - synchronizes two time stamped ordered
    lists
  • merge Performance -gt Performance -gt
    Performance
  • merge a_at_(e1es1) b_at_(e2es2)
  • if eTime e1 lt eTime e2 then e1 merge es1 b
  • else e2 merge a es2
  • merge es2 es2
  • merge es1 es1

13
Notes on step 1
  • Perform has flattened the Music structure into a
    list of events.
  • Events are time stamped, and the final list is in
    time-stamp order.
  • Each event carries information about instrument,
    pitch, and duration.
  • Perform has not dealt with the issue of each note
    etc. must be translated into two midi-events,
    one with a start, and the other with a stop.

14
The Haskell MIDI Library
  • 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

15
Lots of details were ignoring
  • MidiFile MFType Division Track
  • MFType - Int in the range 1,2,3. Were
    interested in MFType 2. This means the midi
    file contains information about multiple tracks
    (up to 15), each playing a different instrument.
    All tracks are played simultaneously.
  • Division - Int representing the time strategy of
    the midi file. We will always use Division 96.
    This means 96 ticks per quarter note.
  • Track - Mevent . This represents the music
    that is played. Note there is a list of Tracks
    each which is a list of Mevents (midi-event).

16
MIDI Events
  • MIDI events come in two flavors.
  • Normal event. NoteOn, NoteOff, or ProgChange
    (switch instrument)
  • Meta event. Change how things are played.
  • Of interest to us SetTempo - change the speed
    of music played.

17
MIDI Library - MIDI Events
  • -- Midi Events
  • 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
  • -- Meta Events
  • data MetaEvent SetTempo MTempo
  • ...
  • deriving (Show, Eq)
  • type MTempo Int

18
Translating
  • performToMidi Performance -gt MidiFile
  • performToMidi pf
  • MidiFile mfType (Ticks division)
  • (map performToMEvs (splitByInst
    pf))
  • mfType 1
  • division 96
  • First, take the performance (a list of events,
    each of which carries information about
    instrument, pitch, and duration), and split it
    into a list of performances, each of which deals
    with only one instrument.
  • splitByInst Performance -gt Performance
  • For each of these single-instrument performances
    turn it into a list of Mevents.
  • performToMEvs Performance -gt Mevent
  • Last, make a MidiFile data type out of it using
    the default MFType and Division

19
Side Trip - Partition
  • partition even 1,2,3,4,6,2,45
  • --gt
  • (2,4,6,2,1,3,45)
  • Partition takes a predicate and a list, and
    returns a pair of lists. The first element of the
    pair is all the elements of the list that meet
    the predicate. The second element all those that
    dont.
  • partition (a -gt Bool) -gt a -gt (a,a)
  • partition p xs
  • foldr select (,) xs
  • where select x (ts,fs)
  • p x (xts,fs)
  • otherwise (ts, xfs)

20
SplitByInst
Instrument
Track
  • splitByInst Performance -gt(MidiChannel,ProgNum
    ,Performance)
  • splitByInst p
  • aux 0 p where
  • aux n
  • aux n pf
  • let i eInst (head pf)
  • (pf1,pf2) partition (\e -gt eInst e
    i) pf
  • n' if n8 then 10 else n1
  • in if iPercussion
  • then (9, 0, pf1) aux n pf2
  • else
  • if ngt15
  • then error
  • "No more than 16
    instruments allowed"
  • else (n, fromEnum i, pf1)
    aux n' pf2

21
PerformToMEvs
  • performToMEvs (MidiChannel,ProgNum,Performance)
    -gt MEvent
  • performToMEvs (ch,pn,perf)
  • let setupInst MidiEvent 0 (ProgChange ch
    pn)
  • setTempo MetaEvent 0 (SetTempo
    tempo)
  • loop
  • loop (ees)
  • let (mev1,mev2) mkMEvents ch e
  • in mev1 insertMEvent mev2 (loop es)
  • in setupInst setTempo loop perf
  • For each event, set up the instrument and the
    tempo, and generate a start and stop event.
  • The start event goes at the beginning of the
    list. But where does the stop event go?

22
First insertMEvent
  • Since the stop event can possibly go any where in
    the list generated we need an function that
    inserts a time-stamped event in the correct
    location in a time-stamped ordered list.
  • insertMEvent MEvent -gt MEvent -gt MEvent
  • insertMEvent ev1 ev1
  • insertMEvent ev1_at_(MidiEvent t1 _)
    evs_at_(ev2_at_(MidiEvent t2 _)evs')
  • if t1 lt t2 then ev1 evs
  • else ev2 insertMEvent ev1 evs'

23
Second mkMEvents
  • mkMEvents MidiChannel -gt Event -gt
    (MEvent,MEvent)
  • mkMEvents mChan (Event eTime t,
  • ePitch p,
  • eDur d )
  • (MidiEvent (toDelta t) (NoteOn mChan p
    127),
  • MidiEvent (toDelta (td))(NoteOff mChan p
    127))
  • toDelta t round (t 4.0 intToFloat division)
  • Generate a NoteOn and a NoteOff for each note at
    the appropriate time.

24
Step 3 Writing a MIDI file
  • -- outputMidiFile String -gt MidiFile -gt IO ()
  • test Music -gt IO ()
  • test m outputMidiFile "test.mid"
  • (performToMidi (perform defCon m))
  • defCon Context -- Defauult Initial Context
  • defCon Context cTime 0,
  • cInst AcousticGrandPiano,
  • cDur metro 120 qn,
  • cKey 0
  • Note it is not until we write the midi-file to
    disk that we move from the pure functional world,
    to the world of actions.

25
Playing Music
  • testWin95 m
  • do test m
  • system "mplayer test.mid
  • return ()
  • testNT m
  • do test m
  • system "mplay32 test.mid
  • return ()
  • testLinux m
  • do test m
  • system "playmidi -rf test.mid
  • return ()

26
Lets Play Some Music!
  • cScale
  • line c 4 qn, d 4 qn, e 4 qn,
  • f 4 qn, g 4 qn, a 4 qn,
  • b 4 qn, c 5 qn
  • testNT cScale

27
(No Transcript)
Write a Comment
User Comments (0)
About PowerShow.com