--
module Music where
type Pitch = (PitchClass, Octave)
data PitchClass = Cf | C | Cs | Df | D | Ds | Ef | E | Es | Ff | F
| Fs | Gf | G | Gs | Af | A | As | Bf | B | Bs
deriving (Eq,Show)
type Octave = Int
data Music = Note Pitch Dur
| Rest Dur
| Music :+: Music
| Music :=: Music
| Tempo (Ratio Int) Music
| Trans Int Music
| Instr IName Music
deriving (Show, Eq)
type Dur = Ratio Int
data IName
= AcousticGrandPiano | BrightAcousticPiano | ElectricGrandPiano
| HonkyTonkPiano | RhodesPiano | ChorusedPiano
| Harpsichord | Clavinet | Celesta
| Glockenspiel | MusicBox
| Vibraphone | Marimba | Xylophone
| TubularBells | Dulcimer | HammondOrgan
| PercussiveOrgan | RockOrgan | ChurchOrgan
| ReedOrgan | Accordion | Harmonica
| TangoAccordion | AcousticGuitarNylon | AcousticGuitarSteel
| ElectricGuitarJazz | ElectricGuitarClean | ElectricGuitarMuted | OverdrivenGuitar
| DistortionGuitar | GuitarHarmonics | AcousticBass
| ElectricBassFingered | ElectricBassPicked | FretlessBass
| SlapBass1 | SlapBass2 | SynthBass1 | SynthBass2
| Violin | Viola | Cello | Contrabass
| TremoloStrings | PizzicatoStrings | OrchestralHarp | Timpani
| StringEnsemble1 | StringEnsemble2 | SynthStrings1
| SynthStrings2 | ChoirAahs | VoiceOohs | SynthVoice
| OrchestraHit | Trumpet | Trombone | Tuba
| MutedTrumpet | FrenchHorn | BrassSection | SynthBrass1
| SynthBrass2 | SopranoSax | AltoSax | TenorSax
| BaritoneSax | Oboe | Bassoon | EnglishHorn | Clarinet
| Piccolo | Flute | Recorder | PanFlute | BlownBottle
| Shakuhachi | Whistle | Ocarina | Lead1Square
| Lead2Sawtooth | Lead3Calliope | Lead4Chiff
| Lead5Charang | Lead6Voice | Lead7Fifths
| Lead8BassLead | Pad1NewAge | Pad2Warm
| Pad3Polysynth | Pad4Choir | Pad5Bowed
| Pad6Metallic | Pad7Halo | Pad8Sweep
| FX1Train | FX2Soundtrack | FX3Crystal
| FX4Atmosphere | FX5Brightness | FX6Goblins
| FX7Echoes | FX8SciFi | Sitar | Banjo | Shamisen
| Koto | Kalimba | Bagpipe | Fiddle | Shanai
| TinkleBell | Agogo | SteelDrums | Woodblock | TaikoDrum
| MelodicDrum | SynthDrum | ReverseCymbal
| GuitarFretNoise | BreathNoise | Seashore
| BirdTweet | TelephoneRing | Helicopter
| Applause | Gunshot | Percussion
deriving (Show,Eq,Ord,Enum)
type AbsPitch = Int
absPitch :: Pitch -> AbsPitch
absPitch (pc,oct) = 12*oct + pcToInt pc
pitch :: AbsPitch -> Pitch
pitch ap = ( [C,Cs,D,Ds,E,F,Fs,G,Gs,A,As,B] !! mod ap 12,
quot ap 12 )
pcToInt :: PitchClass -> Int
pcToInt pc = case pc of
Cf -> -1 -- should Cf be 11?
C -> 0 ; Cs -> 1
Df -> 1 ; D -> 2 ; Ds -> 3
Ef -> 3 ; E -> 4 ; Es -> 5
Ff -> 4 ; F -> 5 ; Fs -> 6
Gf -> 6 ; G -> 7 ; Gs -> 8
Af -> 8 ; A -> 9 ; As -> 10
Bf -> 10 ; B -> 11
Bs -> 12 -- should Bs be 0?
trans :: Int -> Pitch -> Pitch
trans i p = pitch (absPitch p + i)
cf,c,cs,df,d,ds,ef,e,es,ff,f,fs,gf,g,gs,af,a,as,bf,b,bs
:: Octave -> Dur -> Music
cf o = Note (Cf,o); c o = Note (C,o); cs o = Note (Cs,o)
df o = Note (Df,o); d o = Note (D,o); ds o = Note (Ds,o)
ef o = Note (Ef,o); e o = Note (E,o); es o = Note (Es,o)
ff o = Note (Ff,o); f o = Note (F,o); fs o = Note (Fs,o)
gf o = Note (Gf,o); g o = Note (G,o); gs o = Note (Gs,o)
af o = Note (Af,o); a o = Note (A,o); as o = Note (As,o)
bf o = Note (Bf,o); b o = Note (B,o); bs o = Note (Bs,o)
wn, hn, qn, en, sn, tn :: Dur
dhn, dqn, den, dsn :: Dur
wnr, hnr, qnr, enr, snr, tnr :: Music
dhnr, dqnr, denr, dsnr :: Music
wn = 1 ; wnr = Rest wn -- whole
hn = 1%2 ; hnr = Rest hn -- half
qn = 1%4 ; qnr = Rest qn -- quarter
en = 1%8 ; enr = Rest en -- eight
sn = 1%16 ; snr = Rest sn -- sixteenth
tn = 1%32 ; tnr = Rest tn -- thirty-second
dhn = 3%4 ; dhnr = Rest dhn -- dotted half
dqn = 3%8 ; dqnr = Rest dqn -- dotted quarter
den = 3%16 ; denr = Rest den -- dotted eighth
dsn = 3%32 ; dsnr = Rest dsn -- dotted sixteenth
line, chord :: [Music] -> Music
line = foldr (:+:) (Rest 0)
chord = foldr (:=:) (Rest 0)
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]
ex1 = cScale
cMaj = [ n 4 hn | n <- [c,e,g] ]
cMin = [ n 4 wn | n <- [c,ef, g] ]
cMajArp = line cMaj
ex2 = cMajArp
cMajChd = chord cMaj
ex3 = cMajChd
ex4 = line [ chord cMaj, chord cMin ]
delay :: Dur -> Music -> Music
delay d m = Rest d :+: m
ex5 = cScale :=: (delay dhn cScale)
ex6 = line [line cMaj,Trans 12 (line cMaj)]
repeatM :: Music -> Music
repeatM m = m :+: repeatM m
nBeatsRest n note = line ((take n (repeat note)) ++ [qnr])
ex7 = line [e 4 qn, d 4 qn, c 4 qn, d 4 qn,
line [ nBeatsRest 3 (n 4 qn) | n <- [e,d] ],
e 4 qn, nBeatsRest 2 (g 4 qn) ]
pr1, pr2 :: Pitch -> Music
pr1 p = Tempo (5%6)
(Tempo (4%3) (mkLn 1 p qn :+:
Tempo (3%2) (mkLn 3 p en :+:
mkLn 2 p sn :+:
mkLn 1 p qn ) :+:
mkLn 1 p qn) :+:
Tempo (3%2) (mkLn 6 p en))
pr2 p = Tempo (7%6)
(m1 :+:
Tempo (5%4) (mkLn 5 p en) :+:
m1 :+:
Tempo (3%2) m2)
where m1 = Tempo (5%4) (Tempo (3%2) m2 :+: m2)
m2 = mkLn 3 p en
mkLn n p d = line (take n (repeat (Note p d)))
pr12 :: Music
pr12 = pr1 (C,5) :=: pr2 (G,5)
(=:=) :: Dur -> Dur -> Music -> Music
old =:= new = Tempo (new/old)
dur :: Music -> Dur
dur (Note _ d) = d
dur (Rest d) = d
dur (m1 :+: m2) = dur m1 + dur m2
dur (m1 :=: m2) = dur m1 `max` dur m2
dur (Tempo a m) = dur m / a
dur (Trans _ m) = dur m
dur (Instr _ m) = dur m
revM :: Music -> Music
revM n@(Note _ _) = n
revM r@(Rest _) = r
revM (Tempo a m) = Tempo a (revM m)
revM (Trans i m) = Trans i (revM m)
revM (Instr i m) = Instr i (revM m)
revM (m1 :+: m2) = revM m2 :+: revM m1
revM (m1 :=: m2)
= let d1 = dur m1
d2 = dur m2
in if d1>d2 then revM m1 :=: (Rest (d1-d2) :+: revM m2)
else (Rest (d2-d1) :+: revM m1) :=: revM m2
cut :: Dur -> Music -> Music
cut d m | d <= 0 = Rest 0
cut d (Note x d0) = Note x (min d0 d)
cut d (Rest d0) = Rest (min d0 d)
cut d (m1 :=: m2) = cut d m1 :=: cut d m2
cut d (Tempo a m) = Tempo a (cut (d*a) m)
cut d (Trans a m) = Trans a (cut d m)
cut d (Instr a m) = Instr a (cut d m)
cut d (m1 :+: m2) = let m1' = cut d m1
m2' = cut (d - dur m1') m2
in m1' :+: m2'
(/=:) :: Music -> Music -> Music
m1 /=: m2 = cut (min (dur m1) (dur m2)) (m1 :=: m2)
trill :: Int -> Dur -> Music -> Music
trill i d n@(Note p nd)
= if d >= nd then n
else Note p d
:+: trill (negate i) d
(Note (trans i p) (nd-d))
trill i d (Tempo a m) = Tempo a (trill i (d*a) m)
trill i d (Trans a m) = Trans a (trill i d m)
trill i d (Instr a m) = Instr a (trill i d m)
trill _ _ _ = error "Trill input must be a single note"
trill' :: Int -> Dur -> Music -> Music
trill' i sDur m = trill (negate i) sDur (Trans i m)
roll :: Dur -> Music -> Music
roll dur m = trill 0 dur m
trilln :: Int -> Int -> Music -> Music
trilln i nTimes m = trill i (dur m / (nTimes%1)) m
trilln' :: Int -> Int -> Music -> Music
trilln' i nTimes m = trilln (negate i) nTimes (Trans i m)
rolln :: Int -> Music -> Music
rolln nTimes m = trilln 0 nTimes m
data PercussionSound
= AcousticBassDrum -- MIDI Key 35
| BassDrum1 -- MIDI Key 36
| SideStick -- ...
| AcousticSnare | HandClap | ElectricSnare | LowFloorTom
| ClosedHiHat | HighFloorTom | PedalHiHat | LowTom
| OpenHiHat | LowMidTom | HiMidTom | CrashCymbal1
| HighTom | RideCymbal1 | ChineseCymbal | RideBell
| Tambourine | SplashCymbal | Cowbell | CrashCymbal2
| Vibraslap | RideCymbal2 | HiBongo | LowBongo
| MuteHiConga | OpenHiConga | LowConga | HighTimbale
| LowTimbale | HighAgogo | LowAgogo | Cabasa
| Maracas | ShortWhistle | LongWhistle | ShortGuiro
| LongGuiro | Claves | HiWoodBlock | LowWoodBlock
| MuteCuica | OpenCuica | MuteTriangle
| OpenTriangle -- MIDI Key 82
deriving (Show,Eq,Ord,Ix,Enum)
perc :: PercussionSound -> Dur -> Music
perc ps = Note (pitch (fromEnum ps + 35))
funkGroove
= let p1 = perc LowTom qn
p2 = perc AcousticSnare en
in Tempo 3 (Instr Percussion (cut 8 (repeatM
( (p1 :+: qnr :+: p2 :+: qnr :+: p2 :+:
p1 :+: p1 :+: qnr :+: p2 :+: enr)
:=: roll en (perc ClosedHiHat 2) )
)))
--