module Csound.Air.Spec( 	
    toSpec, fromSpec, mapSpec, scaleSpec, addSpec, scalePitch,
    CrossSpec(..),
    crossSpecFilter, crossSpecVocoder, crossSpecFilter1, crossSpecVocoder1
) where
import Data.Default
import Csound.Typed
import Csound.Typed.Opcode
import Csound.Tab(sine)
toSpec :: Sig -> Spec
toSpec asig = pvsanal asig 1024 256 1024 1
fromSpec :: Spec -> Sig
fromSpec = pvsynth
mapSpec :: (Spec -> Spec) -> Sig -> Sig
mapSpec f = fromSpec . f . toSpec
scaleSpec :: Sig -> Sig -> Sig
scaleSpec k = mapSpec $ \x -> pvscale x k
addSpec :: Sig -> Sig -> Sig
addSpec hz = mapSpec $ \x -> pvshift x hz 0
scalePitch :: Sig -> Sig -> Sig
scalePitch n = scaleSpec (semitone n)
at2 :: (Sig -> Sig -> Sig) -> Sig2 -> Sig2 -> Sig2
at2 f (left1, right1) (left2, right2) = (f left1 left2, f right1 right2)
data CrossSpec = CrossSpec 
	{ crossFft 		:: D
	, crossHopSize 	:: D
	, crossScale    :: Sig
	, crossPitch    :: Sig
	, crossMaxTracks :: D
	, crossWinType  :: D
	, crossSearch   :: Sig
	, crossDepth    :: Sig
	, crossThresh   :: Sig
	, crossMinPoints :: Sig
	, crossMaxGap    :: Sig
	}
instance Default CrossSpec where
	def = CrossSpec 
		{ crossFft 		= 12
		, crossHopSize 	= 9
		, crossScale    = 1
		, crossPitch    = 1
		, crossMaxTracks = 500
		, crossWinType  = 1
		, crossSearch   = 1.05
		, crossDepth    = 1
		, crossThresh   = 0.01
		, crossMinPoints = 1
		, crossMaxGap    = 3
		}
crossSpecFilter :: CrossSpec -> Sig2 -> Sig2 -> Sig2
crossSpecFilter spec = at2 (crossSpecFilter1 spec)
crossSpecVocoder :: CrossSpec -> Sig2 -> Sig2 -> Sig2
crossSpecVocoder spec = at2 (crossSpecVocoder1 spec)
crossSpecFilter1 :: CrossSpec -> Sig -> Sig -> Sig
crossSpecFilter1 = crossSpecBy 0
crossSpecVocoder1 :: CrossSpec -> Sig -> Sig -> Sig
crossSpecVocoder1 = crossSpecBy 1
crossSpecBy :: D -> CrossSpec -> Sig -> Sig -> Sig
crossSpecBy imode spec ain1 ain2 = 
	tradsyn (trcross (getPartials ain2) (getPartials ain1) (crossSearch spec) (crossDepth spec) `withD` imode) (crossScale spec) (crossPitch spec) (sig $ crossMaxTracks spec) sine
	where
		getPartials asig = partials fs1 fsi2 (crossThresh spec) (crossMinPoints spec) (crossMaxGap spec) (crossMaxTracks spec)
			where (fs1, fsi2) = pvsifd asig (2 ** (crossFft spec)) (2 ** (crossHopSize spec)) (crossWinType spec)