{- | Demonstration song using with SuperCollider and global effects. This was arranged for the HAL2 meeting in July 2007, Leipzig. -} module Haskore.Interface.SuperCollider.Example.Air where -- import qualified Sound.SC3 as SC import qualified Sound.SC3.UGen.UGen as SCUGen import qualified Sound.SC3.UGen.Oscillator as SCOsci import qualified Sound.SC3.UGen.Filter as SCFilt import qualified Sound.SC3.UGen.Envelope as SCUGEnv import qualified Sound.SC3.UGen.Math as SCMath import Sound.SC3.UGen.Enum (DoneAction(PauseSynth)) import Sound.SC3.UGen.Rate (Rate(KR)) import Sound.SC3.UGen.UGen (UGen) import qualified Haskore.Interface.SuperCollider.Example as Example import qualified Haskore.Interface.SuperCollider.Play as Play import qualified Haskore.Interface.SuperCollider.Schedule as Schedule import qualified Haskore.Interface.SuperCollider.SoundMap as SoundMap import qualified Haskore.Interface.SuperCollider.Schedule.Channel as CSchedule import Haskore.Interface.SuperCollider.Schedule.Channel (rhythmicMusicFromRhythm, rhythmicMusicFromDrum, rhythmicMusicFromMelody, ugenFromSound, installSound) import Haskore.Composition.Chord as Chord import Haskore.Melody as Melody import qualified Haskore.Music as Music import Haskore.Music.Rhythmic as RhyMusic import Haskore.Basic.Duration((%+)) import qualified Haskore.Basic.Duration as Dur import System.Random (randomRs, mkStdGen) import Data.List (genericLength) transposition :: Int transposition = 2 {- bassMelody :: Melody.T (Rational, ()) bassMelody = Music.line $ zipWith (\vel n -> n (vel%1000, ())) (randomRs (0,1000) (mkStdGen 914)) $ -} bassMelodyA0 :: [() -> Melody.T ()] bassMelodyA0 = a 1 den : c 2 en : a 1 sn : d 2 en : e 2 sn : g 2 en : a 1 den : a 1 sn : c 2 en : a 1 sn : c 2 en : d 2 sn : e 2 den : a 1 den : c 2 en : a 1 sn : d 2 en : e 2 sn : g 2 en : a 1 den : a 1 sn : c 2 en : a 1 sn : c 2 en : a 1 sn : g 1 den : [] bassMelodyA1 :: [() -> Melody.T ()] bassMelodyA1 = a 1 den : d 2 en : a 1 sn : e 2 en : fs 2 sn : a 2 en : a 1 den : a 1 sn : d 2 en : a 1 sn : d 2 en : e 2 sn : a 2 den : a 1 den : d 2 en : a 1 sn : e 2 en : fs 2 sn : a 2 en : a 1 den : a 1 sn : c 2 en : d 2 sn : e 2 en : d 2 sn : a 1 den : [] bassMelodyA :: [() -> Melody.T ()] bassMelodyA = bassMelodyA0 ++ bassMelodyA1 -- B == A bassMelodyC :: [() -> Melody.T ()] bassMelodyC = a 1 den : d 2 en : a 1 sn : e 2 en : f 2 sn : a 2 en : a 1 den : a 1 sn : d 2 en : a 1 sn : d 2 en : f 2 sn : a 2 den : a 1 den : d 2 en : a 1 sn : e 2 en : f 2 sn : a 2 en : a 1 den : a 1 sn : c 2 en : d 2 sn : e 2 en : d 2 sn : a 1 den : a 1 den : c 2 en : a 1 sn : d 2 en : e 2 sn : g 2 en : a 1 den : a 1 sn : c 2 en : a 1 sn : c 2 en : d 2 sn : e 2 den : a 1 den : c 2 en : a 1 sn : d 2 en : e 2 sn : g 2 en : a 1 den : a 1 sn : c 2 en : a 1 sn : c 2 en : a 1 sn : g 1 den : [] -- D == A bassMelodyE :: [() -> Melody.T ()] bassMelodyE = a 1 den : d 2 en : a 1 sn : e 2 en : f 2 sn : a 2 en : a 1 den : a 1 sn : d 2 en : a 1 sn : d 2 en : f 2 sn : a 2 den : a 1 den : d 2 en : a 1 sn : e 2 en : f 2 sn : a 2 en : a 1 den : a 1 sn : c 2 en : d 2 sn : e 2 en : d 2 sn : a 1 den : a 1 den : c 2 en : a 1 sn : d 2 en : e 2 sn : g 2 en : a 1 den : a 1 sn : c 2 en : a 1 sn : c 2 en : d 2 sn : e 2 den : a 1 den : c 2 en : a 1 sn : d 2 en : e 2 sn : g 2 en : a 1 den : a 1 sn : c 2 en : a 1 sn : c 2 en : a 1 sn : g 1 den : [] bassMelodyF :: [() -> Melody.T ()] bassMelodyF = a 1 den : c 2 en : a 1 sn : c 2 en : e 2 sn : f 2 en : a 1 den : a 1 sn : c 2 en : a 1 sn : c 2 en : e 2 sn : f 2 den : a 1 den : d 2 en : a 1 sn : d 2 en : f 2 sn : a 2 en : a 1 den : a 1 sn : d 2 en : e 2 sn : f 2 en : e 2 sn : a 1 den : b 1 den : e 2 en : b 1 sn : e 2 en : a 2 sn : b 2 en : b 1 den : b 1 sn : e 2 en : b 1 sn : e 2 en : a 2 sn : b 2 den : b 1 den : e 2 en : b 1 sn : e 2 en : gs 2 sn : b 2 en : b 1 den : b 1 sn : e 2 en : b 1 sn : gs 2 en : e 2 sn : b 1 den : [] bassMelody :: Melody.T () bassMelody = let trans = map (Music.transpose transposition .) in Music.line $ map (Music.crescendo 0.8 . Music.loudness1 0.2 . Music.line . map ($())) $ bassMelodyA : bassMelodyA : bassMelodyA : bassMelodyC : bassMelodyA : bassMelodyE : bassMelodyA : bassMelodyC : trans bassMelodyA : trans bassMelodyF : trans bassMelodyA : trans bassMelodyF : trans bassMelodyA : trans (bassMelodyA0 ++ bassMelodyA0) : [] -- cf. Example.Morph sliceVertInf :: Int -> [a] -> [[a]] sliceVertInf n = map (take n) . iterate (drop n) harpScale :: Melody.T () harpScale = -- could use sliceVert or sliceHoriz let binomDists = map sum $ sliceVertInf 3 $ randomRs (-1,1::Double) (mkStdGen 102) tones = [d,e,a,b] -- properFraction is useless for negative numbers splitFraction x = let n = floor x in (n, x - fromIntegral n) makeNote x = let (oct,p) = splitFraction x in (tones!!floor(p*genericLength tones)) oct sn () in Music.legato qn $ Music.line $ take (round(6*4*dhn/sn)) $ map makeNote $ zipWith (+) binomDists $ iterate (0.02+) (-2) -- envelopedStrings :: Music.Dur -> InstrumentUGen envelopedStrings :: UGen -> SoundMap.Instrument envelopedStrings dur params = let env = SCUGEnv.envGen KR 1 2 0 1 PauseSynth (Example.bridge 3 dur 0.5) in env * Example.strings params chordConfuse :: Melody.T () chordConfuse = Chord.harmonicGen () (2*4*dhn) [a 1, b 1, d 2, e 2, g 2] chordsA :: Melody.T () chordsA = Chord.harmonicGen () (4*dhn) [a 1, c 2, e 2] +:+ Chord.harmonicGen () (4*dhn) [a 1, d 2, fs 2] +:+ Chord.harmonicGen () (4*dhn) [a 2, c 2, e 2] +:+ (Chord.harmonicGen () (4*dhn) [a 2, d 2] =:= (fs 2 (3*dhn) () +:+ g 2 dhn ())) chordsB :: Melody.T () chordsB = let ce = Chord.harmonicGen () (4*dhn) [c 2, e 2] in ce +:+ (d 2 (2*4*dhn) () =:= fs 2 (4*dhn) () +:+ f 2 (4*dhn) ()) +:+ ce chordsBlow :: Melody.T () chordsBlow = a 1 (4*4*dhn) () =:= chordsB chordsBhigh :: Melody.T () chordsBhigh = a 2 (4*4*dhn) () =:= chordsB chordsC :: Melody.T () chordsC = (a 1 (2*dhn) () +:+ a 2 (2*dhn) () =:= c 2 (4*dhn) () =:= e 2 (4*dhn) ()) +:+ (d 2 (2*4*dhn) () =:= fs 2 (2*dhn) () +:+ g 2 (dhn) () +:+ fs 2 (dhn) () +:+ f 2 (2*dhn) () +:+ g 2 (dhn) () +:+ f 2 (dhn) () =:= a 2 (2*4*dhn) ()) +:+ (a 2 (4*dhn) () =:= c 2 (4*dhn) () =:= e 2 (4*dhn) ()) chordsD :: Melody.T () chordsD = (a 1 (2*dhn) () +:+ a 2 (2*dhn) () =:= c 2 (4*dhn) () =:= e 2 (4*dhn) ()) +:+ (d 2 (4*dhn) () =:= fs 2 (2*dhn) () +:+ g 2 (dhn) () +:+ fs 2 (dhn) () =:= a 2 (4*dhn) ()) +:+ (c 2 (2*dhn) () +:+ d 2 (2*dhn) () =:= f 2 (4*dhn) () =:= a 2 (4*dhn) ()) chordsD0 :: Melody.T () chordsD0 = chordsD +:+ (b 1 (4*dhn) () =:= e 2 (4*dhn) () =:= gs 2 (2*dhn) () +:+ a 2 (dhn) () +:+ b 2 (dhn) ()) chordsD1 :: Melody.T () chordsD1 = chordsD +:+ (b 1 (4*dhn) () =:= e 2 (4*dhn) () =:= a 2 (2*dhn) () +:+ gs 2 (2*dhn) ()) chordsE :: Melody.T () chordsE = Chord.harmonicGen () (4*dhn) [a 1, c 2, e 2] +:+ Chord.harmonicGen () (4*dhn) [a 1, d 2, fs 2] +:+ Chord.harmonicGen () (8*dhn) [a 1, c 2, e 2] chords :: Melody.T Double chords = Music.legato wn $ Music.mapDurNote (\dur (Melody.Note () p) -> Melody.Note (2 * Dur.toNumber dur) p) $ chordConfuse +:+ chordsA +:+ chordsBlow +:+ chordsBhigh +:+ chordsC +:+ Music.transpose transposition (chordsD0 +:+ chordsD1 +:+ chordsE) xylophoneSolo :: Melody.T () xylophoneSolo = let build n0 notes = Music.line $ map (\n -> n sn () +:+ n0 sn () +:+ n0 sn ()) notes in build (a 1) [e 2, d 2, e 2, d 2, e 2, d 2, e 2, d 2, e 2, d 2, e 2, g 2, a 2, g 2, e 2, d 2, e 2, d 2, e 2, d 2, e 2, d 2, e 2, d 2, g 2, a 2, c 3, a 2, d 3, c 3, a 2, g 2, f 2, d 2, f 2, d 2, f 2, d 2, f 2, d 2, f 2, d 2, f 2, d 2, g 2, d 2, f 2, d 2, e 2, d 2, e 2, d 2, e 2, d 2, e 2, d 2, a 2, gs 2, g 2, fs 2, f 2, e 2, ds 2, d 2] bassStringMelody :: Melody.T () bassStringMelody = Music.transpose transposition $ Music.line $ map (\n -> n dhn ()) $ a 1 : b 1 : c 2 : e 2 : fs 2 : g 2 : a 2 : b 2 : d 2 : e 2 : f 2 : a 2 : gs 2 : a 2 : b 2 : c 3 : [] melodyA :: Melody.T () melodyA = Music.line $ e 2 (9%+8) () : d 2 den () : c 2 den () : a 2 dqn () : e 2 dqn () : d 2 (5%+16) () : c 2 qn () : d 2 (21%+16) () : e 2 den () : a 1 (15%+16) () : a 1 (5%+16) () : b 1 qn () : c 2 (wn + 5%+16) () : b 1 den () : a 1 den () : d 2 dqn () : e 2 dqn () : c 2 dqn () : d 2 den () : a 1 (15%+8 + 21%+16) () : [] melodyB :: Melody.T () melodyB = Music.take (10 + 11%+16) melodyA +:+ (Music.line $ g 2 (5%+16) () : fs 2 qn () : f 2 (5%+16) () : e 2 ddqn () : []) melody :: Melody.T () melody = Music.rest (4*4*dhn) +:+ melodyB +:+ melodyB +:+ Music.rest (4*4*dhn) +:+ Music.transpose transposition (melodyA +:+ melodyA) {- scsynth -N air.osc _ air.aiff 44100 AIFF int16 -} schedule :: Schedule.T schedule = CSchedule.fromRhythmicMusic $ do bass <- installSound SoundMap.with0Attributes "bass" (Example.fmBass (SCUGen.MCE [0.99,1.01])) guitar <- installSound SoundMap.with0Attributes "guitar" (Example.fmGuitar (SCUGen.MCE [2.99,3.01])) strings <- installSound SoundMap.with1Attribute "strings" envelopedStrings harpsichord <- installSound SoundMap.with0Attributes "harpsichord" Example.harpsichord bassStrings <- installSound SoundMap.with0Attributes "bassstrings" Example.modulatedStrings xylophone <- installSound SoundMap.with0Attributes "xylophone" Example.xylophone hihat <- installSound SoundMap.with0Attributes "hihat" Example.hihat bassdrum <- installSound SoundMap.with0Attributes "bassdrum" Example.bassdrum let lfoSine = 1000 * exp (0.3 * SCOsci.sinOsc KR 0.1 (SCUGen.MCE [-pi/2, 0]) + 0.3 * SCOsci.sinOsc KR (sqrt 0.03) 0) mix = flip SCMath.clip2 1 $ 0.2 * ( ugenFromSound bass + 0.3 * ugenFromSound xylophone + 0.5 * ugenFromSound harpsichord + 3 * SCFilt.lpf (ugenFromSound bassStrings) 1000 + SCFilt.rlpf (0.5 * ugenFromSound strings) lfoSine 0.1 + (let guit = 0.6 * ugenFromSound guitar in guit + SCFilt.combN (SCFilt.lpf guit 500) 0.2 0.2 5) + ugenFromSound hihat + 2*ugenFromSound bassdrum) return (mix, Music.changeTempo 2 $ -- Music.take 10 $ -- Music.drop (4*4*4*dhn) $ (rhythmicMusicFromMelody strings $ Music.transpose (-12) chords) =:= hnr +:+ (rhythmicMusicFromMelody harpsichord harpScale =:= Music.rest (2*4*dhn) +:+ (Music.chord $ (rhythmicMusicFromMelody bass $ Music.transpose (-36) bassMelody) : (rhythmicMusicFromMelody guitar $ Music.transpose (-12) melody) : (Music.rest (3*4*4*dhn) +:+ (rhythmicMusicFromMelody xylophone $ Music.transpose (0) xylophoneSolo)) : (Music.rest (5*4*4*dhn) +:+ (rhythmicMusicFromMelody bassStrings $ Music.transpose (-36) bassStringMelody)) : (Music.replicate (7*4*8 + 2) $ rhythmicMusicFromRhythm bassdrum sn "x.x..x" =:= (Music.replicate 6 $ rhythmicMusicFromDrum hihat sn)) : []))) main :: IO () main = Play.schedule Play.defaultLatency schedule