module Sound where
import Wave
-- data Signal = Signal [Double] deriving(Show, Eq)
double2int :: Double -> Int
double2int = fromInteger . floor
constant :: Double -> Signal
constant x = Signal [x,x..]
silence :: Signal
silence = constant 0
sine :: Double -> Signal
sine f = Signal $ map sin2 [0,1/sampleRate..]
where sin2 x = sin (2 * pi * f * x)
trim :: Signal -> Double -> Signal
trim (Signal s) t = Signal $ take (double2int (time2Samples t)) s
instance Num Signal where
Signal x + Signal y = Signal (zipWith (+) x y)
Signal x * Signal y = Signal (zipWith (*) x y)
Signal x - Signal y = Signal (zipWith (-) x y)
abs (Signal x) = Signal (map abs x)
signum (Signal x) = Signal (map signum x)
fromInteger x = constant (fromInteger x)
instance Fractional Signal where
Signal x / Signal y = Signal (zipWith (/) x y)
fromRational x = constant (fromRational x)
integrate :: Signal -> Signal
integrate (Signal xs) = Signal (integrate' xs 0)
integrate' (x:y:xs) i = trSum : integrate' (y:xs) trSum
where trSum = i + (x+y)/(2*sampleRate)
modulatedSine :: Double -> Signal -> Signal
modulatedSine c m = Signal (map sin fs)
where fs = zipWith (+) (map (\t -> 2*pi*c*t) [0,1/sampleRate..]) (map (c *) i)
Signal i = integrate m
append :: Signal -> Signal -> Signal
append (Signal x) (Signal y) = Signal (x ++ y)
rampUp t = Signal [0,1/(t*sampleRate) .. 1]
hullCurve attack decay decayLevel release =
rampUp attack `append` decayDown `append` releaseDown
where decayDown = 1 - (rampUp decay) * (1 - constant decayLevel)
releaseDown = (1 - (rampUp release)) * (constant decayLevel)
synthLead :: Double -> Signal
synthLead freq = base * hull
where
base = modulatedSine freq (sine freq)
hull = hullCurve 0.004 0.2 0.625 2.0
type Instrument = Double -> Signal
play _ [] = Signal []
play instrument ((freq,len):xs) = go `append` (play instrument xs)
where go = (insSignal `append` silence) `trim` len
insSignal = instrument freq