module Exercise06 where import Data.List import Effects import Types sinPeriod :: Signal sinPeriod sec = sin (2.0*pi*sec) sqwPeriod :: Signal sqwPeriod sec | sec < 0.5 = - 1 | otherwise = 1 sawPeriod :: Signal sawPeriod sec = 2.0*sec -1 triPeriod :: Signal triPeriod sec | sec < 0.5 = 4.0 * sec - 1 | otherwise = -4.0 * sec + 3 silence :: Signal silence = undefined -- 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 sig aDSR semTo secs = adsr aDSR secs fitSig where fitSig s = let wdh = s * f semTo in sig (wdh - fromIntegral (floor wdh)) adsr :: ADSR -> Seconds -> Signal -> Signal adsr (attack, decay, sustain, release) dur sig sec | sec < attack = sec / attack * sig sec | sec < attack+decay = ((sustain - 1) * (sec-attack) / decay + 1) * sig sec | sec < dur-release = sustain * sig sec | otherwise = (-sustain * (sec-(dur-release)) / release + sustain) * sig sec mix :: [SampledSignal] -> SampledSignal mix samps= map norm (foldl vectorAdd [] samps) where norm x = x/fromIntegral(length samps) vectorAdd :: [Double] -> [Double] -> [Double] vectorAdd [] [] = [] vectorAdd (x:xs) [] = x:xs vectorAdd [] (y:ys) = y:ys vectorAdd (x:xs) (y:ys) = x+y:vectorAdd xs ys {-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) -- 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 -- specify the instruments of each track -- try the following instruments with the mario.mid file instrs = cycle [piano, bass] audioTracks = zipWith playNotes instrs tracks audioNoEffects = mixTracks audioTracks [0.8, 0.7] -- audio = audioNoEffects -- To add effects, replace the line above by the line at the end of this comment and change the list off effects to your own effects. -- Note that the effects are applied from right to left, ie. the rightmost effect is applied first. --audio = addEffects [clip 0.7, addGain 4] audioNoEffects --audio = addEffects [slowTremolo (0.6, 1.4) 4000 4000] audioNoEffects {-MC Wettbewerb-} -- I used: -- stack run synth "...\fpv2021ex06-ge25lim\mid\carol_of_the_bells_01.mid" "...\carol_of_the_bells_02.wav" -- and I had to give the whole path audio = addEffects [clip 0.5, bitCrunchSpeed] (applyEffectToInterval (0, 23) (applyEffectToInterval (67, 96) audioNoEffects (slowTremolo (0.6, 1.4) 4000 4000 . addGain 1.6)) (wreck 0.0 0.0001 0.8 . addGain 0.5)) -- If you want to apply an effect only to parts of the signal, you can use the function applyEffectToInterval, as shown below. -- Thereby the first argument specifies the interval to which the effect should be applied in seconds. -- audio = applyEffectToInterval (2, 10) audioNoEffects distortion --audio = applyEffectToInterval (10, 30) audioNoEffects (slowTremolo (0.6, 1.4) 4000 4000) --audio = applyEffectToInterval (25, 45) (applyEffectToInterval (55, 80) audioNoEffects (slowTremolo (0.6, 1.4) 4000 4000)) (wreck 0.0 0.0001 0.6) {-TTEW-}