\subsection{Self-Similar (Fractal) Music.T} \seclabel{self-similar} \begin{haskelllisting} > module Haskore.Example.SelfSim where > > import qualified Haskore.Basic.Pitch as Pitch > import qualified Haskore.Melody as Melody > import qualified Haskore.Music as Music > import Haskore.Music.GeneralMIDI as MidiMusic > import qualified Haskore.Interface.MIDI.Render as Render > import qualified Sound.MIDI.File as MidiFile \end{haskelllisting} An example of self-similar, or fractal, music. \begin{haskelllisting} > data Cluster = Cl SNote [Cluster] -- this is called a Rose tree > type Pat = [SNote] > type SNote = [(Pitch.Absolute,Dur)] -- i.e. a chord > > sim :: Pat -> [Cluster] > sim pat = map mkCluster pat > where mkCluster notes = Cl notes (map (mkCluster . addmult notes) pat) > > > addmult :: (Num a, Num b) => [(a, b)] -> [(a, b)] -> [(a, b)] > addmult pds iss = zipWith addmult' pds iss > where addmult' (p,d) (i,s) = (p+i,d*s) > > simFringe :: (Num a, Eq a) => a -> Pat -> [SNote] > simFringe n pat = fringe n (Cl [(0,0)] (sim pat)) > > fringe :: (Num a, Eq a) => a -> Cluster -> [SNote] > fringe 0 (Cl n _) = [n] > fringe m (Cl _ cls) = concatMap (fringe (m-1)) cls > > -- this just converts the result to Haskore: > simToHask :: [[(Pitch.Absolute, Music.Dur)]] -> Melody.T () > simToHask s = let mkNote (p,d) = Melody.note (Pitch.fromInt p) d () > in line (map (chord . map mkNote) s) > > -- and here are some examples of it being applied: > > sim4 :: Int -> Melody.T () > sim1, sim2, sim12, sim3, sim4s :: Int -> MidiMusic.T > t6, t7, t8, t9, t10 :: MidiFile.T > > sim1 n = MidiMusic.fromMelodyNullAttr MidiMusic.AcousticBass > (transpose (-12) > (changeTempo 4 (simToHask (simFringe n pat1)))) > t6 = Render.generalMidiDeflt (sim1 4) > > sim2 n = MidiMusic.fromMelodyNullAttr MidiMusic.AcousticGrandPiano > (transpose 5 > (changeTempo 4 (simToHask (simFringe n pat2)))) > t7 = Render.generalMidiDeflt (sim2 4) > > sim12 n = sim1 n =:= sim2 n > t8 = Render.generalMidiDeflt (sim12 4) > > sim3 n = MidiMusic.fromMelodyNullAttr MidiMusic.Vibraphone > (transpose 0 > (changeTempo 4 (simToHask (simFringe n pat3)))) > t9 = Render.generalMidiDeflt (sim3 3) > > sim4 n = (transpose 12 > (changeTempo 2 (simToHask (simFringe n pat4')))) > > sim4s n = let s = sim4 n > l1 = MidiMusic.fromMelodyNullAttr MidiMusic.Flute s > l2 = MidiMusic.fromMelodyNullAttr MidiMusic.AcousticBass > (transpose (-36) (Music.reverse s)) > in l1 =:= l2 > > ss :: MidiMusic.T > ss = sim4s 3 > durss :: Music.Dur > durss = Music.dur ss > > t10 = Render.generalMidiDeflt ss > > pat1, pat2, pat3, pat4, pat4' :: [SNote] > pat1 = [[(0,1.0)],[(4,0.5)],[(7,1.0)],[(5,0.5)]] > pat2 = [[(0,0.5)],[(4,1.0)],[(7,0.5)],[(5,1.0)]] > pat3 = [[(2,0.6)],[(5,1.3)],[(0,1.0)],[(7,0.9)]] > pat4' = [[(3,0.5)],[(4,0.25)],[(0,0.25)],[(6,1.0)]] > pat4 = [[(3,0.5),(8,0.5),(22,0.5)],[(4,0.25),(7,0.25),(21,0.25)], > [(0,0.25),(5,0.25),(15,0.25)],[(6,1.0),(9,1.0),(19,1.0)]] \end{haskelllisting}