{-# LANGUAGE Arrows, ExistentialQuantification, FlexibleContexts, ScopedTypeVariables #-}
module Euterpea.IO.Audio.Basics (
outA,
integral,
countDown, countUp,
upsample,
pchToHz, apToHz
) where
import Euterpea.Music
import Euterpea.IO.Audio.Types
import Control.Arrow
import Control.Arrow.Operations
import Control.Arrow.ArrowP
outA :: (Arrow a) => a b b
outA = arr id
integral :: forall a p. (ArrowCircuit a, Clock p) => ArrowP a p Double Double
integral =
let dt = 1 / rate (undefined :: p)
in proc x -> do
rec let i' = i + x * dt
i <- delay 0 -< i'
outA -< i
countDown :: ArrowCircuit a => Int -> a () Int
countDown x = proc _ -> do
rec i <- delay x -< i - 1
outA -< i
countUp :: ArrowCircuit a => a () Int
countUp = proc _ -> do
rec i <- delay 0 -< i + 1
outA -< i
upsample :: forall a b c p1 p2. (ArrowChoice a, ArrowCircuit a, Clock p1, Clock p2, AudioSample c)
=> ArrowP a p1 b c -> ArrowP a p2 b c
upsample f = g
where g = proc x -> do
rec
cc <- delay 0 -< if cc >= r-1 then 0 else cc+1
y <- if cc == 0 then ArrowP (strip f) -< x
else delay zero -< y
outA -< y
r = if outRate < inRate
then error "Cannot upsample a signal of higher rate to lower rate"
else outRate / inRate
inRate = rate (undefined :: p1)
outRate = rate (undefined :: p2)
apToHz :: Floating a => AbsPitch -> a
apToHz ap = 440 * 2 ** (fromIntegral (ap - absPitch (A,4)) / 12)
pchToHz :: Floating a => Pitch -> a
pchToHz = apToHz . absPitch