module Exercise06 where import Data.List import Effects import Types sinPeriod :: Signal sinPeriod x = sin $ 2 * pi * x sqwPeriod :: Signal sqwPeriod x | x < 0.5 = -1 | x > 0.5 = 1 | otherwise = 0 sawPeriod :: Signal sawPeriod x = 2 * x - 1 triPeriod :: Signal triPeriod x = if x < 0.5 then 4 * x - 1 else -4 * x + 3 silence :: Signal silence _ = 0 -- NOTE: the formula is taken from https://pages.mtu.edu/~suits/NoteFreqCalcs.html f :: Semitone -> Hz f n = 440.0 * (2 ** (fromInteger n / 12.0)) osc :: Signal -> ADSR -> Oscillator osc signal ad semitone duration = adsr ad duration newSig where newSig x = signal (f semitone * x - fromInteger (floor $ f semitone * x)) adsr :: ADSR -> Seconds -> Signal -> Signal adsr (attack, decay, sustain, release) duration signal x | x < 0 || x > duration = 0 -- before and after | x < attack = x / attack * signal x -- attack | x < attack + decay = ((sustain - 1) / decay * (x - attack) + 1) * signal x -- decay | x < duration - release = sustain * signal x -- sustaining | otherwise = (-1 * sustain / release * (x - duration + release) + sustain) * signal x -- release mix :: [SampledSignal] -> SampledSignal mix ss = map ((/ fromInteger (genericLength ss)) . sum) $ transpose ss {-WETT-} -- you can add new oscillators here piano :: Oscillator piano = osc sawPeriod (0.01, 0.1, 0.7, 0.2) lead :: Oscillator lead = osc sqwPeriod (0.01, 0.2, 0.3, 0.1) bass :: Oscillator bass = osc sinPeriod (0.001, 0.2, 0.9, 0.1) tri :: Oscillator tri = osc triPeriod (0, 0, 1, 0.5) -- you can add more effects here -- mix the signals with some volume mixTracks :: [SampledSignal] -> [Double] -> SampledSignal mixTracks trks vols = mix $ zipWith (\trk vol -> map (* vol) trk) trks vols -- here we mix it all together and apply the effects notesToSignal :: (Oscillator -> [Note] -> SampledSignal) -> [[Note]] -> SampledSignal notesToSignal playNotes tracks = audio where -- bass bassTrack = zipWith playNotes [bass] $ map (map (\(a, b, c) -> (a - 12, b, c))) tracks bassAudio = addEffects [reduceResolution 1000] $mixTracks bassTrack [1] -- tri triTrack = zipWith playNotes [tri] $ map (map (\(a, b, c) -> (a + 12, b, c))) tracks triAudio = addEffects [delay 1.5] $ mixTracks triTrack [0.6] -- lead pianoTrack = zipWith playNotes [piano] tracks pianoAudio = mixTracks pianoTrack [0.8] -- mix audio = mix [bassAudio, triAudio, pianoAudio] {-TTEW-} {- MCCOMMENT To compile my submission use: stack run synth \2448.mid \2448.wav -- source of the midi file: https://www.cprato.com/en/midi/details/270/deadmau5-2448 -}