module Sound where
import Wave
double2int :: Double -> Int
double2int = fromInteger . floor
constant :: Double -> Signal
constant x = Signal (repeat x)
silence :: Signal
silence = constant 0
sine f = Signal (map sin [0,s..])
where s = 2 * pi * f / sampleRate
trim :: Signal -> Double -> Signal
trim (Signal xs) t = Signal (take (double2int (t * sampleRate)) xs)
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)
negate (Signal x) = Signal (map negate x)
abs (Signal x) = Signal (map abs x)
signum (Signal x) = Signal (map signum x)
fromInteger = constant . fromInteger
instance Fractional Signal where
Signal x / Signal y = Signal (zipWith (/) x y)
recip (Signal x ) = Signal (map recip x)
fromRational = constant . fromRational
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)
integrate' _ _ = []
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 :: Double -> Signal
rampUp t = Signal [0,1/(t*sampleRate)..1]
hullCurve :: Double -> Double -> Double -> Double -> Signal
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 :: Instrument -> [(Double,Double)] -> Signal
play _ [] = Signal []
play instrument ((freq,len):xs) = go `append` (play instrument xs)
where go = (insSignal `append` silence) `trim` len
insSignal = instrument freq
lenSignal = (\(Signal s) -> length s) insSignal
samples = double2int $ time2Samples len