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

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

/*
 *  ResolveGE.scala
 *  (SoundProcesses)
 *
 *  Copyright (c) 2010-2024 Hanns Holger Rutz. All rights reserved.
 *
 *	This software is published under the GNU Affero General Public License v3+
 *
 *
 *  For further information, please contact Hanns Holger Rutz at
 *  [email protected]
 */

package de.sciss.synth

import de.sciss.proc.UGenGraphBuilder
import de.sciss.proc.UGenGraphBuilder.MissingIn
import de.sciss.synth.proc.graph.Attribute

object ResolveGE {
  def test(in: GE): Either[String, Unit] = {
    import ugen._
    in match {
      case _: Constant            => Right(())
      case _: Attribute           => Right(())
      case UnaryOpUGen (_, a   )  => ResolveGE.test(a)
      case BinaryOpUGen(_, a, b)  =>
        for {
          _ <- ResolveGE.test(a).right
          _ <- ResolveGE.test(b).right
        } yield ()

      case _: SampleRate          => Right(())
      case _: NumChannels         => Right(())
      case _                      => Left(s"Element: $in")
    }
  }

  def float(in: GE, builder: UGenGraphBuilder): Either[String, Float] = {
    import ugen._
    in match {
      case Constant(f) => Right(f)

      case a: Attribute =>
        val input = UGenGraphBuilder.Input.Attribute(a.key)
        val opt   = builder.requestInput(input)  // .asInstanceOf[UGenGraphBuilder.Input.Attribute.Value]
        opt.peer.fold[Either[String, Float]] {
          a.default.fold[Either[String, Float]] {
            throw MissingIn(input.key)
          } { sq =>
            if (sq.size == 1) Right(sq.head)
            else Left(s"Cannot use multi-channel element as single Float: $sq")
          }
        } {
          case i: Int     => Right(i.toFloat)
          case d: Double  => Right(d.toFloat)
          case n: Long    => Right(n.toFloat)
          case b: Boolean => Right(if (b) 1f else 0f)
          case other      => Left(s"Cannot convert attribute value to Float: $other")
        }

      case UnaryOpUGen(op: UnaryOpUGen.PureOp, a)  =>
        val af = ResolveGE.float(a, builder)
        af.right.map(op.make1)

      case BinaryOpUGen(op: BinaryOpUGen.PureOp, a, b) =>
        for {
          af <- ResolveGE.float(a, builder).right
          bf <- ResolveGE.float(b, builder).right
        } yield op.make1(af, bf)

      case _: SampleRate   =>
        val sr = builder.server.sampleRate.toFloat
        Right(sr)

      case NumChannels(in0) =>
        var uIns    = Vector.empty[UGenIn]
        var uInsOk  = true
        var exp     = 0
        val args    = in0.expand.outputs
        args.foreach(_.unbubble match {
          case u: UGenIn => if (uInsOk) uIns :+= u
          case g: ugen.UGenInGroup =>
            exp     = math.max(exp, g.numOutputs)
            uInsOk  = false // don't bother adding further UGenIns to uIns
        })
        if (uInsOk) {
          Right(uIns.size.toFloat)
        } else {
          Left(s"Cannot use multi-channel element as single Float: $in0")
        }

      //      case g: ugen.UGenInGroup =>
      //        if (g.numOutputs == 1) resolveFloat(g.outputs.head, builder)
      //        else Left(s"Cannot convert multi-channel element to Float: $in")

      case other => Left(s"Cannot convert element to Float: $other")
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy