module Sound where
import Wave
-- data Signal = Signal [Double] deriving(Show, Eq)
double2int :: Double -> Int
double2int = fromInteger . floor
constant :: Double -> Signal
constant d = Signal (repeat d)
silence :: Signal
silence = constant 0
sine :: Double -> Signal
sine f = Signal $ map sin [0,s..]
where s = 2 * pi * f / sampleRate
trim :: Signal -> Double -> Signal
trim (Signal s) t = Signal (take (double2int (t * sampleRate)) 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)
negate (Signal x) = Signal (map negate 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)
recip (Signal x) = Signal (map recip x)
fromRational x = constant (fromRational x)
integrate :: Signal -> Signal
integrate (Signal xs) = Signal (integrate' xs 0)
integrate' :: [Double] -> Double -> [Double]
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 a) (Signal b) = Signal (a++b)
rampUp :: Double -> Signal
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
lenSignal = (\(Signal s) -> length s) insSignal
samples = double2int $ time2Samples len