Cse536 Functional Programming 1 6/26/2015 Lecture #19, Dec. 6, 2004 Todays Topics –Interpreting Music –Performance –MidiFile Read – Chapters 21 - Interpreting.

Slides:



Advertisements
Similar presentations
Chapter 20 Functional Music Composition. MDL: Music Description Language MDL is a DSL for computer music composition that is even simpler than FAL and.
Advertisements

Peter Rademaker & Robert Stremler. Preview 1.Introduction 2.The Basics 3.Simple Examples 4.Interpretation and Performance 5.MIDI 6.Algebraic Properties.
Recursion 2014 Spring CS32 Discussion Jungseock Joo.
ML Lists.1 Standard ML Lists. ML Lists.2 Lists  A list is a finite sequence of elements. [3,5,9] ["a", "list" ] []  Elements may appear more than once.
ML Lists.1 Standard ML Lists. ML Lists.2 Lists  A list is a finite sequence of elements. [3,5,9] ["a", "list" ] []  ML lists are immutable.  Elements.
Kathleen Fisher cs242 Reading: “A history of Haskell: Being lazy with class”,A history of Haskell: Being lazy with class Section 6.4 and Section 7 “Monads.
Control-Flow Graphs & Dataflow Analysis CS153: Compilers Greg Morrisett.
String is a synonym for the type [Char].
Int 2 Multimedia Revision. Digitised Sound Analogue sound recorded from person, or real instruments.
ML: a quasi-functional language with strong typing Conventional syntax: - val x = 5; (*user input *) val x = 5: int (*system response*) - fun len lis =
File Processing - Indirect Address Translation MVNC1 Hashing Indirect Address Translation Chapter 11.
0 LECTURE 5 LIST COMPREHENSIONS Graham Hutton University of Nottingham.
Quick Sort, Shell Sort, Counting Sort, Radix Sort AND Bucket Sort
Searching Kruse and Ryba Ch and 9.6. Problem: Search We are given a list of records. Each record has an associated key. Give efficient algorithm.
What is a Parser? A parser is a program that analyses a piece of text to determine its syntactic structure  3 means 23+4.
Sorting Chapter Sorting Consider list x 1, x 2, x 3, … x n We seek to arrange the elements of the list in order –Ascending or descending Some O(n.
0 PROGRAMMING IN HASKELL Chapter 7 - Higher-Order Functions.
CSE466 Autumn ‘00- 1 System Functional Requirements  Children’s toy…comes with PC software. Child plays notes on the screen and the device makes corresponding.
Cse321, Programming Languages and Compilers 1 6/19/2015 Lecture #18, March 14, 2007 Syntax directed translations, Meanings of programs, Rules for writing.
Hash Tables1 Part E Hash Tables  
Cse536 Functional Programming 1 6/23/2015 Lecture #17, Dec. 1, 2004 Todays Topics – Higher Order types »Type constructors that take types as arguments.
Honours project: Interim presentation Amanda Crawford – Comp. Sci. Honours
Hash Tables1 Part E Hash Tables  
Chapter 22 From Performance to MIDI. Motivation  Abstractly, an MDL program denotes a Performance.  But a Performance is just a Haskell data structure.
Prof. Fateman CS 164 Lecture 91 Bottom-Up Parsing Lecture 9.
Comp 205: Comparative Programming Languages Lazy Evaluation Errors Evaluation Strategies Infinite Lists…. Lecture notes, exercises, etc., can be found.
1 ES 314 Advanced Programming Lec 2 Sept 3 Goals: Complete the discussion of problem Review of C++ Object-oriented design Arrays and pointers.
Chapter 2: Algorithm Discovery and Design
Sorting (Part II: Divide and Conquer) CSE 373 Data Structures Lecture 14.
Python Programming, 2/e1 Python Programming: An Introduction to Computer Science Chapter 3 Computing with Numbers.
Midi files Here we look at another way of dealing with sound on a computer the use of Midi files. The the Midi file differs from the “wav” file, because.
Problem Solving with Data Structures using Java: A Multimedia Approach Chapter 5: Arrays: A Static Data Structure for Sounds.
CS 61B Data Structures and Programming Methodology July 28, 2008 David Sun.
Chapter 9: Functional Programming in a Typed Language.
0 PROGRAMMING IN HASKELL Chapter 9 - Higher-Order Functions, Functional Parsers.
© M. Gross, ETH Zürich, 2014 Informatik I für D-MAVT (FS 2014) Exercise 12 – Data Structures – Trees Sorting Algorithms.
CS 361 – Chapters 8-9 Sorting algorithms –Selection, insertion, bubble, “swap” –Merge, quick, stooge –Counting, bucket, radix How to select the n-th largest/smallest.
Sorting: Implementation Fundamental Data Structures and Algorithms Klaus Sutner February 24, 2004.
1 CS 457/557: Functional Languages Lists and Algebraic Datatypes Mark P Jones Portland State University.
1 Searching and Sorting Searching algorithms with simple arrays Sorting algorithms with simple arrays –Selection Sort –Insertion Sort –Bubble Sort –Quick.
TJHSST Computer Systems Lab Senior Research Project Designing a Music Scripting Language Casey Mihaloew Abstract: The problem addressed in this.
Chapter 9 Sorting. The efficiency of data handling can often be increased if the data are sorted according to some criteria of order. The first step is.
1 Ch.19 Divide and Conquer. 2 BIRD’S-EYE VIEW Divide and conquer algorithms Decompose a problem instance into several smaller independent instances May.
0 PROGRAMMING IN HASKELL Based on lecture notes by Graham Hutton The book “Learn You a Haskell for Great Good” (and a few other sources) Odds and Ends,
Haskell Chapter 5, Part II. Topics  Review/More Higher Order Functions  Lambda functions  Folds.
CS Class 04 Topics  Selection statement – IF  Expressions  More practice writing simple C++ programs Announcements  Read pages for next.
Chapter 15 Running Time Analysis. Topics Orders of Magnitude and Big-Oh Notation Running Time Analysis of Algorithms –Counting Statements –Evaluating.
Introduction To Algorithm and Data Structures Course Teacher: Moona Kanwal -Algorithm Design -Algorithm Analysis -Data structures -Abstract Data Type.
Searching and Sorting Searching algorithms with simple arrays
What is a Parser? A parser is a program that analyses a piece of text to determine its syntactic structure  3 means 23+4.
ML: a quasi-functional language with strong typing
Theory of Computation Lecture 4: Programs and Computable Functions II
PROGRAMMING IN HASKELL
PROGRAMMING IN HASKELL
PROGRAMMING IN HASKELL
PROGRAMMING IN HASKELL
PROGRAMMING IN HASKELL
PROGRAMMING IN HASKELL
FP Foundations, Scheme In Text: Chapter 14.
PROGRAMMING IN HASKELL
CH 9.2 : Hash Tables Acknowledgement: These slides are adapted from slides provided with Data Structures and Algorithms in C++, Goodrich, Tamassia and.
CH 9.2 : Hash Tables Acknowledgement: These slides are adapted from slides provided with Data Structures and Algorithms in C++, Goodrich, Tamassia and.
PROGRAMMING IN HASKELL
CSE 3302 Programming Languages
Records and Type Classes
PROGRAMMING IN HASKELL
PROGRAMMING IN HASKELL
Music and Audio Computing I A
Records and Type Classes
Presentation transcript:

Cse536 Functional Programming 1 6/26/2015 Lecture #19, Dec. 6, 2004 Todays Topics –Interpreting Music –Performance –MidiFile Read – Chapters 21 - Interpreting Functional Music – Chapter 22 – From Performance to Midi

Cse536 Functional Programming 2 6/26/2015 Haskore Haskore is a Haskell library for constructing digital music The end result is a MIDI-file Today’s lecture: –translating the Music datatype into a MIDI file Haskore Haskell Haskore Abstract High Level Implementation independent MIDI low level bit based implementation standard presentation The point of today’s lecture

Cse536 Functional Programming 3 6/26/2015 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] 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))))))))) Musical notation Algorithm Music algebraic datatype

Cse536 Functional Programming 4 6/26/2015 Need a Shape transformation Algebraic datatype is “tree-like” MIDI-file is linear in shape Need a “flattening” transformation :+: C D E

Cse536 Functional Programming 5 6/26/ 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 –It’s 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 –Lot’s of messy details. But luckily this is handled by the Haskell MIDI library. –First place that non-pure actions are introduced.

Cse536 Functional Programming 6 6/26/2015 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

Cse536 Functional Programming 7 6/26/2015 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 -> Time –eInst :: Event -> Iname –ePitch :: Event -> AbsPitch –eDur :: Event -> 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)

Cse536 Functional Programming 8 6/26/2015 perform :: Context -> Music -> 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 -> Dur -> DurT metro setting dur = 60 / (setting * ratioToFloat dur)

Cse536 Functional Programming 9 6/26/2015 Simple Perform perform t i dt k) m = case m of Note p d -> let dur = ratioToFloat d * dt in [Event t i (transpose p k i) dur] Rest d -> [] m1 :+: m2 -> perform c m1 ++ perform (c {cTime = t + ratioToFloat (dur m1) * dt}) m2 m1 :=: m2 -> merge (perform c m1) (perform c m2) Tempo a m -> perform (c {cDur = dt / ratioToFloat a} ) m Trans p m -> perform (c {cKey = k + p} ) m Instr nm m -> perform (c {cInst = nm} ) m where transpose p k Percussion = absPitch p transpose p k _ = absPitch p + k Quadratic running time

Cse536 Functional Programming 10 6/26/2015 Consider a Music Tree like this: A tree, skewed to the left, will be very expensive to translate: m1 :+: m2 -> 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 -> Music -> (Performance,DurT) :+: D E E D DB

Cse536 Functional Programming 11 6/26/2015 Efficient perform perform :: Context -> Music -> Performance perform c m = fst (perf c m) perf :: Context -> Music -> (Performance, DurT) perf t i dt k) m = case m of Note p d -> let dur = ratioToFloat d * dt in ([Event t i (transpose p k i) dur], dur) Rest d -> ([], ratioToFloat d * dt) m1 :+: m2 -> let (pf1,d1) = perf c m1 (pf2,d2) = perf (c {cTime = t+d1} ) m2 in (pf1++pf2, d1+d2) m1 :=: m2 -> let (pf1,d1) = perf c m1 (pf2,d2) = perf c m2 in (merge pf1 pf2, max d1 d2) Tempo a m -> perf (c {cDur = dt / ratioToFloat a} ) m Trans p m -> perf (c {cKey = k + p} ) m Instr nm m -> perf (c {cInst = nm} ) m where transpose p k Percussion = absPitch p transpose p k _ = absPitch p + k Note how the context changes in recursive calls

Cse536 Functional Programming 12 6/26/2015 merge Consider the case for parallel composition (chords etc.) m1 :=: m2 -> 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 -> Performance -> Performance merge = if eTime e1 < eTime e2 then e1 : merge es1 b else e2 : merge a es2 merge [] es2 = es2 merge es1 [] = es1

Cse536 Functional Programming 13 6/26/2015 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.

Cse536 Functional Programming 14 6/26/2015 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

Cse536 Functional Programming 15 6/26/2015 Lots of details we’re ignoring MidiFile MFType Division [Track] MFType - Int in the range {1,2,3}. We’re 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 Track’s each which is a list of Mevent’ s (midi-event).

Cse536 Functional Programming 16 6/26/2015 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.

Cse536 Functional Programming 17 6/26/2015 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

Cse536 Functional Programming 18 6/26/2015 Translating performToMidi :: Performance -> 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 -> [Performance] For each of these single-instrument performances turn it into a list of Mevent ’s. –performToMEvs :: Performance -> [ Mevent] Last, make a MidiFile data type out of it using the default MFType and Division

Cse536 Functional Programming 19 6/26/2015 Side Trip - Partition partition even [1,2,3,4,6,2,45] --> ([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 don’t. partition :: (a -> Bool) -> [a] -> ([a],[a]) partition p xs = foldr select ([],[]) xs where select x (ts,fs) | p x = (x:ts,fs) | otherwise = (ts, x:fs)

Cse536 Functional Programming 20 6/26/2015 SplitByInst splitByInst :: Performance ->[(MidiChannel,ProgNum,Performance)] splitByInst p = aux 0 p where aux n [] = [] aux n pf = let i = eInst (head pf) (pf1,pf2) = partition (\e -> eInst e == i) pf n' = if n==8 then 10 else n+1 in if i==Percussion then (9, 0, pf1) : aux n pf2 else if n>15 then error "No more than 16 instruments allowed" else (n, fromEnum i, pf1) : aux n' pf2 Track Instrument

Cse536 Functional Programming 21 6/26/2015 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 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?

Cse536 Functional Programming 22 6/26/2015 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 -> [MEvent] -> [MEvent] insertMEvent ev1 [] = [ev1] insertMEvent t1 _) t2 _):evs') = if t1 <= t2 then ev1 : evs else ev2 : insertMEvent ev1 evs'

Cse536 Functional Programming 23 6/26/2015 Second: mkMEvents 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) Generate a NoteOn and a NoteOff for each note at the appropriate time.

Cse536 Functional Programming 24 6/26/2015 Step 3: Writing a MIDI file -- outputMidiFile :: String -> MidiFile -> IO () test :: Music -> 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.

Cse536 Functional Programming 25 6/26/2015 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 ()}

Cse536 Functional Programming 26 6/26/2015 Let’s Play Some Music!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

Cse536 Functional Programming 27 6/26/2015 :+: D E E D DB