{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses,
  TypeSynonymInstances, FlexibleContexts #-} 
                                                                                                    
-- | Multiple Out 
                  
module CsoundExpr.Base.MultiOut(
    MultiOut,
    mo,
    moA,
    moK,
    moI,
    mo1,
    mo2,
    mo3,
    mo4,
    mo5,
    mo6,
    mo7,
    mo8,
    moA1,
    moA2,
    moA3,
    moA4,
    moA6,
    moA8,
    moK1,
    moK2,
    moK3,
    moK4,
    moK6,
    moK8,
    moI1,
    moI2,
    moI3,
    moI4,
    moI6,
    moI8)
where 
      
import CsoundExpr.Translator.Types
import CsoundExpr.Base.Types
import CsoundExpr.Translator.ExprTree.ExprTree
import CsoundExpr.Translator.Cs.CsTree
import CsoundExpr.Translator.Cs.IM 
                                   
data MultiOut = MultiOut CsTree 
                                
 
instance IM CsTree MultiOut where
        from = MultiOut
        to (MultiOut a) = a 
                                                                                        
 
labelMO :: (IM CsTree a) => Int -> MultiOut -> a
labelMO id x = from $ outPort id $ (to x :: CsTree) 
                                                    
 
rateOf :: (X a) => a -> Rate
rateOf a = head $ exprType $ exprTreeTag t1
  where t1 = to $ from t0 `asTypeOf` a :: CsTree
        t0 = pure (opc "") [] :: CsTree 
                                                                                                                                     
-- | extracts list of values
 
mo :: (X a) => Int -> MultiOut -> [a]
mo n x = map (flip labelMO x) [0 .. n - 1] 
                                           
 
moA :: Int -> MultiOut -> [Arate]
moA = mo 
         
 
moK :: Int -> MultiOut -> [Krate]
moK = mo 
         
 
moI :: Int -> MultiOut -> [Irate]
moI = mo 
         
 
moA1 :: MultiOut -> (Arate)
moA1 = mo1 
           
 
moA2 :: MultiOut -> (Arate, Arate)
moA2 = mo2 
           
 
moA3 :: MultiOut -> (Arate, Arate, Arate)
moA3 = mo3 
           
 
moA4 :: MultiOut -> (Arate, Arate, Arate, Arate)
moA4 = mo4 
           
 
moA6 :: MultiOut -> (Arate, Arate, Arate, Arate, Arate, Arate)
moA6 = mo6 
           
 
moA8 ::
     MultiOut ->
       (Arate, Arate, Arate, Arate, Arate, Arate, Arate, Arate)
moA8 = mo8 
             
 
moK1 :: MultiOut -> (Krate)
moK1 = mo1 
           
 
moK2 :: MultiOut -> (Krate, Krate)
moK2 = mo2 
           
 
moK3 :: MultiOut -> (Krate, Krate, Krate)
moK3 = mo3 
           
 
moK4 :: MultiOut -> (Krate, Krate, Krate, Krate)
moK4 = mo4 
           
 
moK6 :: MultiOut -> (Krate, Krate, Krate, Krate, Krate, Krate)
moK6 = mo6 
           
 
moK8 ::
     MultiOut ->
       (Krate, Krate, Krate, Krate, Krate, Krate, Krate, Krate)
moK8 = mo8 
           
             
 
moI1 :: MultiOut -> (Irate)
moI1 = mo1 
           
 
moI2 :: MultiOut -> (Irate, Irate)
moI2 = mo2 
           
 
moI3 :: MultiOut -> (Irate, Irate, Irate)
moI3 = mo3 
           
 
moI4 :: MultiOut -> (Irate, Irate, Irate, Irate)
moI4 = mo4 
           
 
moI6 :: MultiOut -> (Irate, Irate, Irate, Irate, Irate, Irate)
moI6 = mo6 
           
 
moI8 ::
     MultiOut ->
       (Irate, Irate, Irate, Irate, Irate, Irate, Irate, Irate)
moI8 = mo8 
           
             
 
mo1 :: (X a0) => MultiOut -> (a0)
mo1 x = (y0)
  where y0 = rateMO rs $ labelMO 0 x
        rs = [rateOf y0] 
                                                                           
 
mo2 :: (X a0, X a1) => MultiOut -> (a0, a1)
mo2 x = (y0, y1)
  where y0 = rateMO rs $ labelMO 0 x
        y1 = rateMO rs $ labelMO 1 x
        rs = [rateOf y0, rateOf y1] 
                                                                                                                               
 
mo3 :: (X a0, X a1, X a2) => MultiOut -> (a0, a1, a2)
mo3 x = (y0, y1, y2)
  where y0 = rateMO rs $ labelMO 0 x
        y1 = rateMO rs $ labelMO 1 x
        y2 = rateMO rs $ labelMO 2 x
        rs = [rateOf y0, rateOf y1, rateOf y2] 
                                                                                                                                                                                   
 
mo4 :: (X a0, X a1, X a2, X a3) => MultiOut -> (a0, a1, a2, a3)
mo4 x = (y0, y1, y2, y3)
  where y0 = rateMO rs $ labelMO 0 x
        y1 = rateMO rs $ labelMO 1 x
        y2 = rateMO rs $ labelMO 2 x
        y3 = rateMO rs $ labelMO 3 x
        rs = [rateOf y0, rateOf y1, rateOf y2, rateOf y3] 
                                                                                                                                                                                                                                       
 
mo5 ::
      (X a0, X a1, X a2, X a3, X a4) => MultiOut -> (a0, a1, a2, a3, a4)
mo5 x = (y0, y1, y2, y3, y4)
  where y0 = rateMO rs $ labelMO 0 x
        y1 = rateMO rs $ labelMO 1 x
        y2 = rateMO rs $ labelMO 2 x
        y3 = rateMO rs $ labelMO 3 x
        y4 = rateMO rs $ labelMO 4 x
        rs = [rateOf y0, rateOf y1, rateOf y2, rateOf y3, rateOf y4] 
                                                                                                                                                                                                                                                                                           
 
mo6 ::
      (X a0, X a1, X a2, X a3, X a4, X a5) =>
      MultiOut -> (a0, a1, a2, a3, a4, a5)
mo6 x = (y0, y1, y2, y3, y4, y5)
  where y0 = rateMO rs $ labelMO 0 x
        y1 = rateMO rs $ labelMO 1 x
        y2 = rateMO rs $ labelMO 2 x
        y3 = rateMO rs $ labelMO 3 x
        y4 = rateMO rs $ labelMO 4 x
        y5 = rateMO rs $ labelMO 5 x
        rs
          = [rateOf y0, rateOf y1, rateOf y2, rateOf y3, rateOf y4,
             rateOf y5] 
                                                                                                                                                                                                                                                                                                                                                                      
 
mo7 ::
      (X a0, X a1, X a2, X a3, X a4, X a5, X a6) =>
      MultiOut -> (a0, a1, a2, a3, a4, a5, a6)
mo7 x = (y0, y1, y2, y3, y4, y5, y6)
  where y0 = rateMO rs $ labelMO 0 x
        y1 = rateMO rs $ labelMO 1 x
        y2 = rateMO rs $ labelMO 2 x
        y3 = rateMO rs $ labelMO 3 x
        y4 = rateMO rs $ labelMO 4 x
        y5 = rateMO rs $ labelMO 5 x
        y6 = rateMO rs $ labelMO 6 x
        rs
          = [rateOf y0, rateOf y1, rateOf y2, rateOf y3, rateOf y4,
             rateOf y5, rateOf y6] 
                                                                                                                                                                                                                                                                                                                                                                                                                          
 
mo8 ::
      (X a0, X a1, X a2, X a3, X a4, X a5, X a6, X a7) =>
      MultiOut -> (a0, a1, a2, a3, a4, a5, a6, a7)
mo8 x = (y0, y1, y2, y3, y4, y5, y6, y7)
  where y0 = rateMO rs $ labelMO 0 x
        y1 = rateMO rs $ labelMO 1 x
        y2 = rateMO rs $ labelMO 2 x
        y3 = rateMO rs $ labelMO 3 x
        y4 = rateMO rs $ labelMO 4 x
        y5 = rateMO rs $ labelMO 5 x
        y6 = rateMO rs $ labelMO 6 x
        y7 = rateMO rs $ labelMO 7 x
        rs
          = [rateOf y0, rateOf y1, rateOf y2, rateOf y3, rateOf y4,
             rateOf y5, rateOf y6, rateOf y7]