module Csound.Air.Granular(
	GrainRate, GrainSize, Pointer, ConstPitchSig,
	
	RndGrainySpec(..),
	grainy, grainy1, rndGrainy, rndGrainy1,
	ptrGrainy, rndPtrGrainy, 
	ptrGrainySnd, ptrGrainySnd1,
	
	SndwarpSpec(..), 
	sndwarp, sndwarpst, sndwarpSnd, sndwarpSnd1,
	ptrSndwarp, ptrSndwarpst, ptrSndwarpSnd, ptrSndwarpSnd1,
	
	SyncgrainSpec(..), RndSyncgrainSpec(..),
	syncgrain, syncgrainSnd, syncgrainSnd1,
	rndSyncgrain, rndSyncgrainSnd, rndSyncgrainSnd1,
	
	GranuleSpec(..), GranuleMode(..),
	granule, granuleSnd, granuleSnd1,
	
	PartikkelSpec(..),
	partikkel, 
	
	Fof2Spec(..),
	fof2, fof2Snd, fof2Snd1,
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	grainyDelay, rndGrainyDelay, sndwarpDelay, 
	syncgrainDelay, rndSyncgrainDelay, partikkelDelay, fofDelay,	
	
	
	
	
	grainyFx, rndGrainyFx, sndwarpFx, 
	syncgrainFx, rndSyncgrainFx, partikkelFx, fofFx,
	
	csdSndwarp, csdSndwarpst, csdSyncgrain, csdGranule, csdPartikkel
) where
import Data.Default
import Data.Boolean
import Data.List(isSuffixOf)
import Control.Applicative hiding ((<*))
import Control.Monad.Trans.Class
import Csound.Dynamic hiding (int, when1, whens)
import Csound.Typed
import Csound.Typed.Opcode hiding(partikkel, granule, grain, syncgrain, sndwarp, sndwarpst, fof2)
import qualified Csound.Typed.Opcode as C(partikkel, granule, grain, syncgrain, sndwarp, sndwarpst, fof2)
import Csound.Air.Wav(PitchSig, TempoSig, lengthSnd)
import Csound.Air.Fx(tabDelay, MaxDelayTime, DelayTime, Feedback, Balance)
import Csound.Tab
import Csound.SigSpace
w1 = "/home/anton/house2.wav"
w2 = "/home/anton/fox.wav"
w3 = "/home/anton/music/csd/ClassGuit.wav"
type GrainRate 	= Sig
type GrainSize 	= Sig
type Pointer 	= Sig
type ConstPitchSig = D
data PartikkelSpec = PartikkelSpec
	{ partikkelDistribution		:: Sig
	, partikkelDisttab			:: Tab
	, partikkelSync				:: Sig
	, partikkelEnv2amt			:: Sig
	, partikkelEnv2tab			:: Tab
	, partikkelEnv_attack		:: Tab
	, partikkelEnv_decay		:: Tab
	, partikkelSustain_amount	:: Sig
	, partikkelA_d_ratio		:: Sig	
	, partikkelAmp 				:: Sig	
	, partikkelGainmasks 		:: Tab	
	, partikkelSweepshape 		:: Sig
	, partikkelWavfreqstarttab 	:: Tab
	, partikkelWavfreqendtab 	:: Tab	
	, partikkelWavfm 			:: Sig
	, partikkelFmamptab 		:: Tab
	, partikkelFmenv 			:: Tab
	, partikkelCosine 			:: Tab	
	, partikkelNumpartials 		:: Sig
	, partikkelChroma 			:: Sig
	, partikkelChannelmasks 	:: Tab	
	, partikkelRandommask 		:: Sig	
	, partikkelWaveamptab 		:: Tab	
	, partikkelWavekeys 		:: [Sig]
	, partikkelMax_grains		:: D
	}
instance Default PartikkelSpec where
	def = PartikkelSpec 
		{ partikkelDistribution		= 1
		, partikkelDisttab			= setSize 32768 $ lins [0, 1, 1]
		, partikkelSync				= 0
		, partikkelEnv2amt			= 1
		, partikkelEnv2tab			= setSize 4096 $ winSync [1]
		, partikkelEnv_attack		= noTab
		, partikkelEnv_decay		= noTab
		, partikkelSustain_amount	= 0
		, partikkelA_d_ratio		= 0		
		, partikkelAmp 				= 1
		, partikkelGainmasks 		= noTab		
		, partikkelSweepshape 		= 0
		, partikkelWavfreqstarttab 	= noTab
		, partikkelWavfreqendtab 	= noTab
		, partikkelWavfm 			= 0
		, partikkelFmamptab 		= noTab
		, partikkelFmenv 			= noTab
		, partikkelCosine 			= setSize 8193 $ sines3 [(1, 1, 90)]		
		, partikkelNumpartials 		= 1
		, partikkelChroma 			= 1
		, partikkelChannelmasks 	= noTab
		, partikkelRandommask 		= 0
		, partikkelWaveamptab 		= noTab		
		, partikkelWavekeys 		= [1] 
		, partikkelMax_grains		= 1000
		}
data RndGrainySpec = RndGrainySpec 
	{ rndGrainyPitch	:: Sig
	, rndGrainyPos		:: Sig
	, rndGrainyDur		:: Sig
	}
instance Default RndGrainySpec where
	def = RndGrainySpec
		{ rndGrainyPitch	= 0.25
		, rndGrainyPos		= 0.1
		, rndGrainyDur		= 0.2
		}
partikkel :: PartikkelSpec -> GrainRate -> GrainSize -> PitchSig -> [Tab] -> [Pointer] -> Sig
partikkel spec kgrainrate kgrainsize kpitch ifiltab apnter = mul 0.2 res
	where
		res = csdPartikkel 
				kgrainrate (partikkelDistribution spec) (partikkelDisttab spec) (partikkelSync spec)
				(partikkelEnv2amt spec) (partikkelEnv2tab spec) (partikkelEnv_attack spec) (partikkelEnv_decay spec)
				(partikkelSustain_amount spec) (partikkelA_d_ratio spec) (kgrainsize * 1000) (partikkelAmp spec)
				(partikkelGainmasks spec) kwavfreq (partikkelSweepshape spec) (partikkelWavfreqstarttab spec)
				(partikkelWavfreqendtab spec) (partikkelWavfm spec) (partikkelFmamptab spec) (partikkelFmenv spec)
				(partikkelCosine spec) kgrainrate (partikkelNumpartials spec) (partikkelChroma spec)
				(partikkelChannelmasks spec) (partikkelRandommask spec) 
				filtab1 filtab2 filtab3 filtab4
				(partikkelWaveamptab spec)
				apnter1 apnter2 apnter3 apnter4
				keys1 keys2 keys3 keys4
				(partikkelMax_grains spec)
		iorig		= 		1 / (ftlen(head ifiltab)/getSampleRate) 
		kwavfreq	= 		sig iorig * kpitch
		filtab1 : filtab2 : filtab3 : filtab4 : _ = cycle ifiltab 
		apnter1 : apnter2 : apnter3 : apnter4 : _ = cycle apnter
		keys1   : keys2   : keys3   : keys4   : _ = cycle (partikkelWavekeys spec)
grainy1 :: GrainRate -> GrainSize -> TempoSig -> PitchSig -> String -> Sig
grainy1 = grainyChn 1
grainy :: GrainRate -> GrainSize -> TempoSig -> PitchSig -> String -> Sig2
grainy kgrainrate kgrainsize kspeed kfreqFactor file = (f 1, f 2)	
	where f n = grainyChn n kgrainrate kgrainsize kspeed kfreqFactor file
grainyChn :: Int -> GrainRate -> GrainSize -> TempoSig -> PitchSig -> String -> Sig
grainyChn n kgrainrate kgrainsize kspeed kpitch file = 
	ptrGrainy kgrainrate kgrainsize kpitch (grainyTab n file) (grainyPtr kspeed file)
rndGrainy1 :: RndGrainySpec -> GrainRate -> GrainSize -> TempoSig -> PitchSig -> String -> SE Sig
rndGrainy1 = rndGrainyChn 1
rndGrainy :: RndGrainySpec -> GrainRate -> GrainSize -> TempoSig -> PitchSig -> String -> SE Sig2
rndGrainy spec kgrainrate kgrainsize kspeed kfreqFactor file = do
	asig1 <- f 1140
	asig2 <- f 2
	return (asig1, asig2)
	where f n = rndGrainyChn n spec kgrainrate kgrainsize kspeed kfreqFactor file
rndGrainyChn :: Int -> RndGrainySpec -> GrainRate -> GrainSize -> TempoSig -> PitchSig -> String -> SE Sig
rndGrainyChn n spec kgrainrate kgrainsize kspeed kpitch file = 
	rndPtrGrainy spec kgrainrate kgrainsize kpitch (grainyTab n file) (grainyPtr kspeed file)
ptrGrainy :: GrainRate -> GrainSize -> PitchSig -> Tab -> Pointer -> Sig
ptrGrainy kgrainrate kgrainsize kcent ifiltab apnter = 
	partikkel def kgrainrate kgrainsize kcent [ifiltab] [apnter]
ptrGrainySnd :: GrainRate -> GrainSize -> PitchSig -> String -> Pointer -> Sig2
ptrGrainySnd kgrainrate kgrainsize kcent file apnter = (f (wavs file 0 WavLeft), f (wavs file 0 WavRight))
	where f tab = partikkel def kgrainrate kgrainsize kcent [tab] [apnter / sig (lengthSnd file)]
ptrGrainySnd1 :: GrainRate -> GrainSize -> PitchSig -> String -> Pointer -> Sig
ptrGrainySnd1 kgrainrate kgrainsize kcent file apnter = f (wavs file 0 WavLeft)
	where f tab = partikkel def kgrainrate kgrainsize kcent [tab] [apnter / sig (lengthSnd file)]
rndPtrGrainy :: RndGrainySpec -> GrainRate -> GrainSize -> PitchSig -> Tab -> Pointer -> SE Sig
rndPtrGrainy rndSpec kgrainrate kgrainsize kpitch ifiltab apnter = do
	kpitchRandVal <- rand (rndGrainyPitch rndSpec)
	arndpos <- linrand (rndGrainyPos rndSpec)
	krndsize <- rand (rndGrainyDur rndSpec)
	return $ ptrGrainy kgrainrate (kgrainsize + krndsize) (kpitch + kpitchRandVal) ifiltab (apnter + arndpos)
grainyTab :: Int -> String -> Tab
grainyTab n file = wavs file 0 (if n == 1 then WavLeft else WavRight)
grainyPtr :: Sig -> String -> Sig
grainyPtr kspeed file = apnter
	where
		ifildur = filelen $ text file		
		apnter = phasor (kspeed / sig ifildur)
data GranuleMode = GranuleForward | GranuleBackward | GranuleRandom
fromGranuleMode :: GranuleMode -> D
fromGranuleMode x = case x of
	GranuleForward -> 1
	GranuleBackward -> 1
	GranuleRandom -> 0
data GranuleSpec = GranuleSpec 
	{ granuleGap   :: Sig
	, granuleVoice :: D
	, granuleRatio :: D
	, granuleMode  :: GranuleMode
	, granuleSkip_os :: D
	, granuleGap_os :: D
	, granuleSize_os :: D
	, granuleSeed :: D
	, granuleAtt   :: D
	, granuleDec   :: D	
	}
instance Default GranuleMode where
	def = GranuleForward
instance Default GranuleSpec where
	def = GranuleSpec 
		{ granuleGap = 0
		, granuleVoice = 64
		, granuleRatio = 1
		, granuleMode  = def
		, granuleSkip_os = 0.5
		, granuleGap_os = 0.5
		, granuleSize_os = 0.5
		, granuleSeed = 0.5
		, granuleAtt   = 0.3
		, granuleDec   = 0.3	
		}
toPercent = (100 * )
granule :: GranuleSpec -> [ConstPitchSig] -> GrainSize -> Tab -> Sig
granule spec chord kgsize ifn = granuleWithLength len spec chord kgsize ifn
	where len = nsamp ifn / getSampleRate
granuleSnd :: GranuleSpec -> [ConstPitchSig] -> GrainSize -> String -> Sig2
granuleSnd spec chord kgsize file = 
	( granuleWithLength len spec chord kgsize (wavs file 0 WavLeft)
	, granuleWithLength len spec chord kgsize (wavs file 0 WavRight))
	where len = filelen $ text file
granuleSnd1 :: GranuleSpec -> [ConstPitchSig] -> GrainSize -> String -> Sig
granuleSnd1 spec chord kgsize file = granuleWithLength len spec chord kgsize (wavs file 0 WavLeft)
	where len = filelen $ text file
granuleWithLength :: D -> GranuleSpec -> [ConstPitchSig] -> GrainSize -> Tab -> Sig
granuleWithLength len spec chord kgsize ifn = mul 0.2 res 
	where
		kgap 		= granuleGap spec
		kamp 		= 1
		ivoice      = granuleVoice spec
		iratio      = granuleRatio spec
		imode       = fromGranuleMode $ granuleMode spec
		ithd        = 0
		ipshift     = int $ min (length $ chord) 4
		igskip      = 0
		igskip_os   = toPercent $ granuleSkip_os spec
		ilength     = len
		igap_os     = toPercent $ granuleGap_os spec
		igsize_os   = toPercent $ granuleSize_os spec
		iatt        = toPercent $ granuleAtt spec
		idec        = toPercent $ granuleDec spec
		iseed       = granuleSeed spec
		ipitch1 : ipitch2 : ipitch3 : ipitch4 : _ = chord ++ [1, 1, 1, 1]
		
		
		res  = csdGranule kamp ivoice iratio imode ithd ifn ipshift igskip
				igskip_os ilength kgap igap_os kgsize igsize_os iatt idec `withDs` [iseed, ipitch1, ipitch2, ipitch3, ipitch4]
main = print "hi"
data SyncgrainSpec = SyncgrainSpec 
	{ syncgrainWin 	 :: Tab
	, syncgrainOverlap :: D	
	}
data RndSyncgrainSpec = RndSyncgrainSpec 
	{ rndSyncTimescale :: Sig
	, rndSyncgrainPitch :: Sig
	, rndSyncgrainGrainDur :: Sig
	}
instance  Default SyncgrainSpec where
	def = SyncgrainSpec 
		{ syncgrainWin 	   = setSize 16384 $ sines3 [(0.5, 1, 0)]
		, syncgrainOverlap   = 25		
		}
instance Default RndSyncgrainSpec where
	def = RndSyncgrainSpec 
		{ rndSyncTimescale     = 0.5
		, rndSyncgrainPitch    = 0.51 
		, rndSyncgrainGrainDur = 0.2
		}
syncgrain :: SyncgrainSpec -> GrainSize -> TempoSig -> PitchSig -> Tab -> Sig 
syncgrain spec kgrdur ktimescale kpitch ftab = mul 0.2 res
	where
		kgroverlap = sig $ (syncgrainOverlap spec) / 2
		ko1 = int' (kgroverlap + 0.15)
		kfr = ko1 / kgrdur 
		kps = 1 / ko1
		awp = phasor (sig $ getSampleRate / ftlen ftab)
		res = csdSyncgrain 1 kfr kpitch kgrdur (kps * ktimescale) ftab (syncgrainWin spec) (syncgrainOverlap spec)
rndSyncgrain :: RndSyncgrainSpec -> SyncgrainSpec -> GrainSize -> TempoSig -> PitchSig -> Tab -> SE Sig
rndSyncgrain rndSpec spec kgrdur ktimescale kpitch ftab = do	
		rndSyncGrainDur <- rnd (rndSyncgrainGrainDur rndSpec)
		rndSyncGrainPitch <- birnd (rndSyncgrainPitch rndSpec)
		rndSyncGrainTimescale <- birnd (rndSyncTimescale rndSpec)
		let kgroverlap = sig $ (syncgrainOverlap spec) / 2
		    ko1 = int' (kgroverlap + 0.15)
		    kgr = kgrdur + rndSyncGrainDur
		    kfr = ko1 / kgr 
		    kps = 1 / ko1
		    awp = phasor (sig $ getSampleRate / ftlen ftab)
		    res = csdSyncgrain 1 kfr (kpitch + rndSyncGrainPitch) kgr (kps * ktimescale + rndSyncGrainTimescale) ftab (syncgrainWin spec) (syncgrainOverlap spec)
		return res
syncgrainSnd :: SyncgrainSpec -> GrainSize -> TempoSig -> PitchSig -> String -> Sig2
syncgrainSnd spec kgrdur ktimescale kpitch  file = 
	(f $ wavs file 0 WavLeft, f $ wavs file 0 WavRight)
	where f = syncgrain spec kgrdur ktimescale kpitch 
syncgrainSnd1 :: SyncgrainSpec -> GrainSize -> TempoSig -> PitchSig -> String -> Sig
syncgrainSnd1 spec kgrdur ktimescale kpitch  file = f $ wavs file 0 WavLeft	
	where f = syncgrain spec kgrdur ktimescale kpitch 
rndSyncgrainSnd :: RndSyncgrainSpec -> SyncgrainSpec -> GrainSize -> TempoSig -> PitchSig -> String -> SE Sig2
rndSyncgrainSnd rndSpec spec kgrdur ktimescale kpitch  file = do
	aleft  <- f $ wavs file 0 WavLeft
	aright <- f $ wavs file 0 WavRight
	return (aleft, aright)
	where f = rndSyncgrain rndSpec spec kgrdur ktimescale kpitch 
rndSyncgrainSnd1 :: RndSyncgrainSpec -> SyncgrainSpec -> GrainSize -> TempoSig -> PitchSig -> String -> SE Sig
rndSyncgrainSnd1 rndSpec spec kgrdur ktimescale kpitch  file = f $ wavs file 0 WavLeft	
	where f = rndSyncgrain rndSpec spec kgrdur ktimescale kpitch 
data SndwarpSpec = SndwarpSpec 
	{ sndwarpWinSize :: D
	, sndwarpRandw   :: D
	, sndwarpOvelrap :: D
	, sndwarpWin     :: Tab
	}
instance Default SndwarpSpec where
	def = SndwarpSpec
		{ sndwarpWinSize  = 0.1
		, sndwarpRandw    = 0.3
		, sndwarpOvelrap  = 50
		, sndwarpWin      = setSize 16384 $ sines3 [(0.5, 1, 0)]
		}
sndwarp :: SndwarpSpec -> TempoSig -> PitchSig -> Tab -> Sig
sndwarp spec kspeed xresample ftab = mul 0.2 $ csdSndwarp 1 kspeed xresample ftab 0 
	(getSampleRate * sndwarpWinSize spec) (getSampleRate * sndwarpRandw spec) 
	(sndwarpOvelrap spec) (sndwarpWin spec) 0
sndwarpst :: SndwarpSpec -> TempoSig -> PitchSig -> Tab -> Sig2
sndwarpst spec xspeed xresample ftab = mul 0.2 $ csdSndwarpst 1 xspeed xresample ftab 0 
	(getSampleRate * sndwarpWinSize spec) (getSampleRate * sndwarpRandw spec) 
	(sndwarpOvelrap spec) (sndwarpWin spec) 0
sndwarpSnd :: SndwarpSpec -> TempoSig -> PitchSig -> String -> Sig2
sndwarpSnd spec kspeed xresample file = sndwarpst spec kspeed xresample (wavs file 0 WavAll)
sndwarpSnd1 :: SndwarpSpec -> TempoSig -> PitchSig -> String -> Sig
sndwarpSnd1 spec kspeed xresample file = sndwarp spec kspeed xresample (wavs file 0 WavLeft)
ptrSndwarp :: SndwarpSpec -> PitchSig -> Tab -> Pointer -> Sig
ptrSndwarp spec xresample ftab xptr = mul 0.2 $ csdSndwarp 1 xptr xresample ftab 0 
	(getSampleRate * sndwarpWinSize spec) (getSampleRate * sndwarpRandw spec) 
	(sndwarpOvelrap spec) (sndwarpWin spec) 1
ptrSndwarpst :: SndwarpSpec -> PitchSig -> Tab -> Pointer -> Sig2
ptrSndwarpst spec xresample ftab xptr = csdSndwarpst 1 xptr xresample ftab 0 
	(getSampleRate * sndwarpWinSize spec) (getSampleRate * sndwarpRandw spec) 
	(sndwarpOvelrap spec) (sndwarpWin spec) 1
ptrSndwarpSnd :: SndwarpSpec -> PitchSig -> String -> Pointer -> Sig2
ptrSndwarpSnd spec xresample file xptr = ptrSndwarpst spec xresample (wavs file 0 WavAll) xptr
ptrSndwarpSnd1 :: SndwarpSpec -> PitchSig -> String -> Pointer -> Sig
ptrSndwarpSnd1 spec xresample file xptr = ptrSndwarp spec xresample (wavs file 0 WavLeft) xptr
data Fof2Spec = Fof2Spec 
	{ fof2TimeMod  :: Sig
	, fof2PitchMod :: Sig
	, fof2Oct   :: Sig 
	, fof2Band  :: Sig
	, fof2Rise  :: Sig
	, fof2Decay :: Sig
	, fof2Gliss :: Sig
	, fof2Win   :: Tab
	}
instance Default Fof2Spec where
	def = Fof2Spec
		{ fof2TimeMod  	= 0.2
		, fof2PitchMod 	= 0 
		, fof2Oct   		= 0
		, fof2Band  		= 0
		, fof2Rise  		= 0.5
		, fof2Decay 		= 0.5
		, fof2Gliss 		= 0
		, fof2Win   		= setSize 8192 $ sines4 [(0.5, 1, 270, 1)]
		}
fof2Snd :: Fof2Spec -> GrainRate -> GrainSize -> TempoSig -> String -> Sig2
fof2Snd spec kgrainrate kgrainsize kspeed file = (f 1, f 2)
	where f n = fof2Chn n spec kgrainrate kgrainsize kspeed file
fof2Snd1 :: Fof2Spec -> GrainRate -> GrainSize -> TempoSig -> String -> Sig
fof2Snd1 spec kgrainrate kgrainsize kspeed file = f 1
	where f n = fof2Chn n spec kgrainrate kgrainsize kspeed file
fof2Chn :: Int -> Fof2Spec -> GrainRate -> GrainSize -> TempoSig -> String -> Sig
fof2Chn n spec kgrainrate kgrainsize kspeed file = 
	fof2 spec kgrainrate kgrainsize (grainyTab n file) (grainyPtr kspeed file)
fof2 :: Fof2Spec -> GrainRate -> GrainSize -> Tab -> Pointer -> Sig
fof2 spec grainRate grainSize buf kphs = go (ftlen buf) buf kphs
	where
		kfund = grainRate
		kris  = fof2Rise spec
		kdec  = fof2Decay spec
		kband = fof2Band spec
		koct  = fof2Oct spec
		kgliss = fof2Gliss spec
		go :: D -> Tab -> Sig -> Sig
		go tabLen buf kphs = do			    
			csdFof2 (ampdbfs (8)) kfund kform koct kband (kris * kdur) 
				kdur (kdec * kdur) 100	giLive giSigRise 86400 kphs kgliss
			where
				kdur = grainSize / kfund				
				kform = (sig $ getSampleRate / tabLen)	
				giSigRise = fof2Win spec
				giLive = buf
fofDelay :: MaxDelayTime -> DelayTime -> Feedback -> Balance -> Fof2Spec -> GrainRate -> GrainSize -> Sig -> SE Sig
fofDelay maxLength delTim kfeed kbalance spec grainRate grainSize asig = do
	rndTmod <- rnd31 kTmod 1
	rndFmod <- rnd31 kFmod 1
	tabDelay (go rndFmod tabLen) maxLength (delTim + rndTmod) kfeed kbalance asig
	where 
		kTmod = fof2TimeMod spec
		kFmod = fof2PitchMod spec
		kfund = grainRate
		kris  = fof2Rise spec
		kdec  = fof2Decay spec
		kband = fof2Band spec
		koct  = fof2Oct spec
		kgliss = fof2Gliss spec
		tabLen = tabSizeSecondsPower2 maxLength
		go :: Sig -> D -> Tab -> Sig -> SE Sig
		go kFmod tabLen buf kphs = do			    
			return $ csdFof2 (ampdbfs (8)) kfund kform koct kband (kris * kdur) 
						kdur (kdec * kdur) 100	giLive giSigRise 86400 kphs kgliss
			where
				kdur = grainSize / kfund				
				kform   = (1+kFmod)*(sig $ getSampleRate / tabLen)			
				giSigRise = fof2Win spec
				giLive = buf
grainyDelay :: MaxDelayTime -> DelayTime -> Feedback -> Balance -> GrainRate -> GrainSize -> PitchSig -> Sig -> SE Sig
grainyDelay maxDel delTime kfeed kbalance grainRate grainSize pitch asig = tabDelay go maxDel delTime kfeed kbalance asig
	where go tab ptr = return $ ptrGrainy grainRate grainSize pitch tab ptr
rndGrainyDelay :: MaxDelayTime -> DelayTime -> Feedback -> Balance -> RndGrainySpec -> GrainRate -> GrainSize -> PitchSig -> Sig -> SE Sig
rndGrainyDelay  maxDel delTime kfeed kbalance spec grainRate grainSize pitch asig = tabDelay go maxDel delTime kfeed kbalance asig
	where go = rndPtrGrainy spec grainRate grainSize pitch
sndwarpDelay :: MaxDelayTime -> DelayTime -> Feedback -> Balance -> SndwarpSpec -> PitchSig -> Sig -> SE Sig
sndwarpDelay maxDel delTime kfeed kbalance spec pitch asig = tabDelay go maxDel delTime kfeed kbalance asig
	where go tab ptr = return $ ptrSndwarp spec pitch tab (sec2rel tab ptr)
syncgrainDelay :: MaxDelayTime -> DelayTime -> Feedback -> Balance -> SyncgrainSpec -> GrainSize -> TempoSig -> PitchSig -> Sig -> SE Sig
syncgrainDelay maxDel delTime kfeed kbalance spec grainSize tempo pitch asig = tabDelay go maxDel delTime kfeed kbalance asig
	where go tab _ = return $ syncgrain spec grainSize tempo pitch tab
rndSyncgrainDelay :: MaxDelayTime -> DelayTime -> Feedback -> Balance -> RndSyncgrainSpec -> SyncgrainSpec -> GrainSize -> TempoSig -> PitchSig -> Sig -> SE Sig
rndSyncgrainDelay maxDel delTime kfeed kbalance rndSpec spec grainSize tempo pitch asig = tabDelay go maxDel delTime kfeed kbalance asig
	where go tab _ = rndSyncgrain rndSpec spec grainSize tempo pitch tab
partikkelDelay :: MaxDelayTime -> DelayTime -> Feedback -> Balance -> PartikkelSpec -> GrainRate -> GrainSize -> PitchSig -> Sig -> SE Sig
partikkelDelay maxDel delTime kfeed kbalance spec grainRate grainSize pitch asig = tabDelay go maxDel delTime kfeed kbalance asig
	where go tab ptr = return $ partikkel spec grainRate grainSize pitch [tab] [ptr]
fxFeed = 0
fxBalance = 1
fxMaxLength = 1
fxDelTime = 0.05
type GrainDelay a = MaxDelayTime -> DelayTime -> Feedback -> Balance -> a
toGrainFx :: GrainDelay a -> a
toGrainFx f = f fxMaxLength fxDelTime fxFeed fxBalance
grainyFx :: GrainRate -> GrainSize -> PitchSig -> Sig -> SE Sig
grainyFx = toGrainFx grainyDelay
rndGrainyFx :: RndGrainySpec -> GrainRate -> GrainSize -> PitchSig -> Sig -> SE Sig
rndGrainyFx = toGrainFx rndGrainyDelay
sndwarpFx :: SndwarpSpec -> PitchSig -> Sig -> SE Sig
sndwarpFx = toGrainFx sndwarpDelay
syncgrainFx :: SyncgrainSpec -> GrainSize -> TempoSig -> PitchSig -> Sig -> SE Sig
syncgrainFx = toGrainFx syncgrainDelay
rndSyncgrainFx :: RndSyncgrainSpec -> SyncgrainSpec -> GrainSize -> TempoSig -> PitchSig -> Sig -> SE Sig
rndSyncgrainFx = toGrainFx rndSyncgrainDelay
partikkelFx :: PartikkelSpec -> GrainRate -> GrainSize -> PitchSig -> Sig -> SE Sig
partikkelFx = toGrainFx partikkelDelay
fofFx :: Fof2Spec -> GrainRate -> GrainSize -> Sig -> SE Sig
fofFx = toGrainFx fofDelay
csdPartikkel :: Tuple a => Sig	-> Sig -> Tab -> Sig -> Sig -> Tab -> Tab -> Tab -> Sig	-> Sig -> Sig -> Sig -> Tab -> Sig 	-> Sig 	-> Tab-> Tab -> Sig	-> Tab -> Tab -> Tab -> Sig -> Sig -> Sig -> Tab -> Sig -> Tab -> Tab -> Tab -> Tab -> Tab -> Sig -> Sig -> Sig -> Sig -> Sig -> Sig -> Sig -> Sig -> D -> a
csdPartikkel b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 b21 b22 b23 b24 b25 b26 b27 b28 b29 b30 b31 b32 b33 b34 b35 b36 b37 b38 b39 b40 = pureTuple $ f <$> unSig b1 <*> unSig b2 <*> unTab b3 <*> unSig b4 <*> unSig b5 <*> unTab b6 <*> unTab b7 <*> unTab b8 <*> unSig b9 <*> unSig b10 <*> unSig b11 <*> unSig b12 <*> unTab b13 <*> unSig b14 <*> unSig b15 <*> unTab b16 <*> unTab b17 <*> unSig b18 <*> unTab b19 <*> unTab b20 <*> unTab b21 <*> unSig b22 <*> unSig b23 <*> unSig b24 <*> unTab b25 <*> unSig b26 <*> unTab b27 <*> unTab b28 <*> unTab b29 <*> unTab b30 <*> unTab b31 <*> unSig b32 <*> unSig b33 <*> unSig b34 <*> unSig b35 <*> unSig b36 <*> unSig b37 <*> unSig b38 <*> unSig b39 <*> unD b40
    where f a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20 a21 a22 a23 a24 a25 a26 a27 a28 a29 a30 a31 a32 a33 a34 a35 a36 a37 a38 a39 a40 = 
    			mopcs "partikkel" ([Ar,Ar,Ar,Ar,Ar,Ar,Ar,Ar],[Ar,Kr,Ir,Ar,Kr,Ir,Ir,Ir,Kr,Kr,Kr,Kr,Ir,Kr,Kr,Ir,Ir,Ar,Ir,Kr,Ir,Kr,Kr,Kr,Ir,Kr,Kr,Kr,Kr,Kr,Ir,Ar,Ar,Ar,Ar,Kr,Kr,Kr,Kr,Ir,Ir]) [a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31,a32,a33,a34,a35,a36,a37,a38,a39,a40]
csdSyncgrain :: Sig -> Sig -> Sig -> Sig -> Sig -> Tab -> Tab -> D -> Sig
csdSyncgrain b1 b2 b3 b4 b5 b6 b7 b8 = Sig $ f <$> unSig b1 <*> unSig b2 <*> unSig b3 <*> unSig b4 <*> unSig b5 <*> unTab b6 <*> unTab b7 <*> unD b8
	where f a1 a2 a3 a4 a5 a6 a7 a8 = opcs "syncgrain" [(Ar, [Kr,Kr,Kr,Kr,Kr,Ir,Ir,Ir])] [a1, a2, a3, a4, a5, a6, a7, a8]
csdGranule :: Sig -> D -> D -> D -> D -> Tab -> D -> D -> D -> D -> Sig -> D -> Sig -> D -> D -> D -> Sig
csdGranule = C.granule
csdSndwarp :: Sig -> Sig -> Sig -> Tab -> D -> D -> D -> D -> Tab -> D -> Sig
csdSndwarp = C.sndwarp
csdSndwarpst :: Sig -> Sig -> Sig -> Tab -> D -> D -> D -> D -> Tab -> D -> Sig2
csdSndwarpst = C.sndwarpst
csdFof2 = C.fof2