All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.sciss.synth.GE.scala Maven / Gradle / Ivy

/*
 *  GE.scala
 *  (ScalaCollider)
 *
 *  Copyright (c) 2008-2013 Hanns Holger Rutz. All rights reserved.
 *
 *  This software is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either
 *  version 2, june 1991 of the License, or (at your option) any later version.
 *
 *  This software is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 *  General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public
 *  License (gpl.txt) along with this software; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *
 *  For further information, please contact Hanns Holger Rutz at
 *  [email protected]
 */

package de.sciss.synth

import scala.{Seq => SSeq}
import collection.breakOut
import collection.immutable.{ IndexedSeq => IIdxSeq }
import ugen.{ChannelProxy, Flatten, Poll, Impulse, LinExp, LinLin, BinaryOp, UnaryOp, MulAdd}

/**
 *    The UGen graph is constructed from interconnecting graph elements (GE).
 *    Graph elements can be decomposed into a sequence of UGenIn objects.
 *    Graph elements are ordinary UGens, UGen proxies, Control proxies,
 *    Constants, and collections of UGen inputs which result from
 *    multichannel expansion (UGenInSeq). 
 */
object GE {
   // XXX don't we expect Multi[ GE[ R ]] ?
   implicit def fromSeq( xs: SSeq[ GE ]) : GE = xs match {
      case SSeq( x ) => x
      case _ => SeqImpl( xs.toIndexedSeq )
   }

   implicit def fromIntSeq( xs: SSeq[ Int ]) : GE = xs match {
      case SSeq( single ) => single: Constant
      case _ => SeqImpl( xs.map( i => Constant( i.toFloat ))( breakOut ))
   }

   implicit def fromFloatSeq( xs: SSeq[ Float ]) : GE = xs match {
      case SSeq( x ) => x: Constant
      case _ => SeqImpl( xs.map( f => Constant( f ))( breakOut ))
   }

   implicit def fromDoubleSeq( xs: SSeq[ Double ]) : GE = xs match {
      case SSeq( x ) => x: Constant
      case _ => SeqImpl( xs.map( d => Constant( d.toFloat ))( breakOut ))
   }

   def fromUGenIns( xs: SSeq[ UGenIn ]) : GE = SeqImpl2( xs.toIndexedSeq )

//   implicit def fromSeq[ R <: Rate, G ]( x: Seq[ G ])( implicit view: G => GE[ R ]) : GE[ R ] = {
//      x match {
//         case Seq( single ) => single // Multi.Joint( single )
//         case _ => GESeq[ R ]( x.map( view )( breakOut ))
//      }
//   }

   @SerialVersionUID(-5589376755121907882L) private final case class SeqImpl( elems: IIdxSeq[ GE ]) extends GE {
def numOutputs = elems.size
      def expand : UGenInLike = UGenInGroup( elems.map( _.expand ))
      def rate = MaybeRate.reduce( elems.map( _.rate ): _* )
      override def displayName = "GE.Seq"
      override def toString = displayName + elems.mkString( "(", ",", ")" )
   }
   private final case class SeqImpl2( elems: IIdxSeq[ UGenIn ]) extends GE {
def numOutputs = elems.size
      def expand : UGenInLike = UGenInGroup( elems )
      def rate = MaybeRate.reduce( elems.map( _.rate ): _* )
      override def displayName = "GE.Seq"
      override def toString = displayName + elems.mkString( "(", ",", ")" )
   }

//   object Seq {
////      implicit def toIndexedSeq[ R <: Rate ]( g: Seq[ R ]) : IIdxSeq[ GE[ R ]] = g.elems
////      def apply[ R <: Rate ]( elems: IIdxSeq[ GE[ R ]]) : Seq[ R ] = new SeqImpl( elems )
//      def apply[ R <: Rate ]( xs: GE[ R ]* ) : Seq[ R ] = new SeqImpl( xs.toIndexedSeq )
//      def apply( xs: UGenIn* ) : Seq[ Rate ] = new SeqImpl2( xs.toIndexedSeq )
//   }
//   sealed trait Seq[ R <: Rate ] extends GE[ R ]

   /**
    * Simply a trait composed of `Lazy.Expander[UGenInLike]` and `GE`
    */
   trait Lazy extends Lazy.Expander[ UGenInLike ] with GE
   
//   implicit def ops( g: GE ) : Ops = new Ops( g )
   
   final class Ops( g: GE ) {
      def `\\`( index: Int ) = ChannelProxy( g, index )
   
      def madd( mul: GE, add: GE ) = MulAdd( g, mul, add )
   
      def flatten = Flatten( g )
   
      def poll: Poll = poll()
   
      /**
       * Polls the output values of this graph element, and prints the result to the console.
       * This is a convenient method for wrapping this graph element in a `Poll` UGen.
       *
       * @param   trig     a signal to trigger the printing. If this is a constant, it is
       *    interpreted as a frequency value and an `Impulse` generator of that frequency
       *    is used instead.
       * @param   label    a string to print along with the values, in order to identify
       *    different polls. Using the special label `"#auto"` (default) will generated
       *    automatic useful labels using information from the polled graph element
       * @param   trigID   if greater then 0, a `"/tr"` OSC message is sent back to the client
       *    (similar to `SendTrig`)
       *
       * @see  [[de.sciss.synth.ugen.Poll]]
       */
      def poll( trig: GE = 10, label: Optional[ String ] = None, trigID: GE = -1 ) : Poll = {
         val trig1 = trig match {
            case Constant( freq ) => Impulse( (g.rate ?| audio) max control, freq, 0 )  // XXX good? or throw an error? should have a maxRate?
            case other => other
         }
         Poll( trig1.rate, trig1, g, label.getOrElse( g.displayName ), trigID  )
      }
   
      import UnaryOp._
   
      // unary ops
      def unary_- : GE   = Neg.make( g )
   // def bitNot : GE	         = BitNot.make( g )
      def abs : GE       = Abs.make( g )
   // def toFloat : GE	         = UnOp.make( 'asFloat, this )
   // def toInteger : GE	      = UnOp.make( 'asInteger, this )
      def ceil : GE      = Ceil.make( g )
      def floor : GE     = Floor.make( g )
      def frac : GE      = Frac.make( g )
      def signum : GE    = Signum.make( g )
      def squared : GE   = Squared.make( g )
      def cubed : GE     = Cubed.make( g )
      def sqrt : GE      = Sqrt.make( g )
      def exp : GE       = Exp.make( g )
      def reciprocal : GE= Reciprocal.make( g )
      def midicps : GE   = Midicps.make( g )
      def cpsmidi : GE   = Cpsmidi.make( g )
      def midiratio : GE = Midiratio.make( g )
      def ratiomidi : GE = Ratiomidi.make( g )
      def dbamp : GE     = Dbamp.make( g )
      def ampdb : GE     = Ampdb.make( g )
      def octcps : GE    = Octcps.make( g )
      def cpsoct : GE    = Cpsoct.make( g )
      def log : GE       = Log.make( g )
      def log2 : GE      = Log2.make( g )
      def log10 : GE     = Log10.make( g )
      def sin : GE       = Sin.make( g )
      def cos : GE       = Cos.make( g )
      def tan : GE       = Tan.make( g )
      def asin : GE      = Asin.make( g )
      def acos : GE      = Acos.make( g )
      def atan : GE      = Atan.make( g )
      def sinh : GE      = Sinh.make( g )
      def cosh : GE      = Cosh.make( g )
      def tanh : GE      = Tanh.make( g )
   // def rand : GE              = UnOp.make( 'rand, this )
   // def rand2 : GE             = UnOp.make( 'rand2, this )
   // def linrand : GE           = UnOp.make( 'linrand, this )
   // def bilinrand : GE         = UnOp.make( 'bilinrand, this )
   // def sum3rand : GE          = UnOp.make( 'sum3rand, this )
      def distort : GE   = Distort.make( g )
      def softclip : GE  = Softclip.make( g )
   // def coin : GE              = UnOp.make( 'coin, this )
   // def even : GE              = UnOp.make( 'even, this )
   // def odd : GE               = UnOp.make( 'odd, this )
   // def rectWindow : GE        = UnOp.make( 'rectWindow, this )
   // def hanWindow : GE         = UnOp.make( 'hanWindow, this )
   // def welWindow : GE         = UnOp.make( 'sum3rand, this )
   // def triWindow : GE         = UnOp.make( 'triWindow, this )
      def ramp : GE      = Ramp.make( g )
      def scurve : GE    = Scurve.make( g )
   // def isPositive : GE        = UnOp.make( 'isPositive, this )
   // def isNegative : GE        = UnOp.make( 'isNegative, this )
   // def isStrictlyPositive : GE= UnOp.make( 'isStrictlyPositive, this )
   // def rho : GE               = UnOp.make( 'rho, this )
   // def theta : GE             = UnOp.make( 'theta, this )
   
      import BinaryOp._
   
      // binary ops
      private def binOp( op: BinaryOp.Op, b: GE ) : GE =
         op.make( /* r.getOrElse( this.rate, b.rate ), */ g, b )
   
      def +( b: GE) = binOp( Plus, b )
   //      Plus.make /*[ R, S, T ]*/( r.getOrElse( this.rate, b.rate ), this, b )
      
      def -( b: GE) = binOp( Minus, b )
   
      def *( b: GE) = binOp( Times, b )
   
   // def div( b: GE[ /*S,*/ UGenIn /*[ S ]*/])/**/ = : GE      = IDiv.make /*[ R, S, T ]*/( /* r.out,*/ this, b )
   
      def / ( b: GE) = binOp( Div, b )
   
      def % ( b: GE) = binOp( Mod, b )
   
      def === ( b: GE) = binOp( Eq, b )
   
      def !== ( b: GE) = binOp( Neq, b )
   
      def < ( b: GE) = binOp( Lt, b )
   
      def > ( b: GE) = binOp( Gt, b )
   
      def <= ( b: GE) = binOp( Leq, b )
   
      def >= ( b: GE) = binOp( Geq, b )
   
      def min ( b: GE) = binOp( Min, b )
   
      def max( b: GE) = binOp( Max, b )
   
      def & ( b: GE) = binOp( BitAnd, b )
   
      def | ( b: GE) = binOp( BitOr, b )
   
      def ^ ( b: GE) = binOp( BitXor, b )
   
   // def Lcm( b: GE[ /*S,*/ UGenIn /*[ S ]*/])/**/ = : GE      = Lcm.make /*[ R, S, T ]*/( /* r.out,*/ this, b )
   // def Gcd( b: GE[ /*S,*/ UGenIn /*[ S ]*/])/**/ = : GE      = Gcd.make /*[ R, S, T ]*/( /* r.out,*/ this, b )
   
      def round ( b: GE) = binOp( Round, b )
   
      def roundup ( b: GE) = binOp( Roundup, b )
   
      def trunc ( b: GE) = binOp( Trunc, b )
   
      def atan2 ( b: GE) = binOp( Atan2, b )
   
      def hypot ( b: GE) = binOp( Hypot, b )
   
      def hypotx ( b: GE) = binOp( Hypotx, b )
   
      def pow ( b: GE) = binOp( Pow, b )
   
   // def <<( b: GE[ /*S,*/ UGenIn /*[ S ]*/])/**/ = : GE       = <<.make /*[ R, S, T ]*/( /* r.out,*/ this, b )
   // def >>( b: GE[ /*S,*/ UGenIn /*[ S ]*/])/**/ = : GE       = >>.make /*[ R, S, T ]*/( /* r.out,*/ this, b )
   // def unsgnRghtShift( b: GE[ /*S,*/ UGenIn /*[ S ]*/])/**/ = : GE = UnsgnRghtShift.make /*[ R, S, T ]*/( /* r.out,*/ this, b )
   // def fill( b: GE[ /*S,*/ UGenIn /*[ S ]*/])/**/ = : GE     = Fill.make /*[ R, S, T ]*/( /* r.out,*/ this, b )
   
      def ring1 ( b: GE) = binOp( Ring1, b )
   
      def ring2 ( b: GE) = binOp( Ring2, b )
   
      def ring3 ( b: GE) = binOp( Ring3, b )
   
      def ring4 ( b: GE) = binOp( Ring4, b )
   
      def difsqr ( b: GE) = binOp( Difsqr, b )
   
      def sumsqr ( b: GE) = binOp( Sumsqr, b )
   
      def sqrsum ( b: GE) = binOp( Sqrsum, b )
   
      def sqrdif ( b: GE) = binOp( Sqrdif, b )
   
      def absdif ( b: GE) = binOp( Absdif, b )
   
      def thresh ( b: GE) = binOp( Thresh, b )
   
      def amclip ( b: GE) = binOp( Amclip, b )
   
      def scaleneg ( b: GE) = binOp( Scaleneg, b )
   
      def clip2 ( b: GE) = binOp( Clip2, b )
   
      def excess ( b: GE) = binOp( Excess, b )
   
      def fold2 ( b: GE) = binOp( Fold2, b )
   
      def wrap2 ( b: GE) = binOp( Wrap2, b )
   
      def firstarg ( b: GE) = binOp( Firstarg, b )
   
   // def rrand( b: GE[ /*S,*/ UGenIn /*[ S ]*/])/**/ = : GE    = Rrand.make /*[ R, S, T ]*/( /* r.out,*/ this, b )
   // def exprrand( b: GE[ /*S,*/ UGenIn /*[ S ]*/])/**/ = : GE = Exprrand.make /*[ R, S, T ]*/( /* r.out,*/ this, b )
   
      def linlin( srcLo: GE, srcHi: GE, dstLo: GE, dstHi: GE ) : GE =
         LinLin( /* rate, */ g, srcLo, srcHi, dstLo, dstHi )
   
      def linexp( srcLo: GE, srcHi: GE, dstLo: GE, dstHi: GE ) : GE =
         LinExp( g.rate, g, srcLo, srcHi, dstLo, dstHi ) // should be highest rate of all inputs? XXX
   }
}
/**
 * The main trait used in synthesis graph, a graph element, abbreviated as `GE`.
 *
 * Graph elements are characterized by having a calculation rate (possibly unknown),
 * and they embody future UGens, which are created by invoking the `expand` method.
 * For each ugen in SuperCollider, there is a corresponding graph element defined
 * in the `ugen` package, and these elements take again graph elements as arguments.
 * Multi-channel expansion is thus deferred to the transition from `SynthGraph` to `UGenGraph`.
 *
 * Currently, also a lot of unary and binary operations are directly defined on the `GE` trait,
 * although they might go into a separate `GEOps` implicit class in future versions.
 *
 * @see [[de.sciss.synth.SynthGraph]]
 */
trait GE {
   def rate: MaybeRate
   def expand: UGenInLike
   def displayName: String
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy