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

de.sciss.synth.proc.AuralAttribute.scala Maven / Gradle / Ivy

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

package de.sciss.synth.proc

import de.sciss.lucre.event.Observable
import de.sciss.lucre.stm.{Obj, Sys}
import de.sciss.lucre.synth.{AudioBus, NodeRef, Sys => SSys}
import de.sciss.synth.ControlSet
import de.sciss.synth.proc.impl.{AuralAttributeImpl => Impl}

import scala.collection.immutable.{IndexedSeq => Vec}
import scala.language.{higherKinds, implicitConversions}

object AuralAttribute {
  def apply[S <: SSys[S]](key: String, value: Obj[S], observer: Observer[S])
                         (implicit tx: S#Tx, context: AuralContext[S]): AuralAttribute[S] =
    Impl(key, value, observer)

  // ---- Observer ----

  trait Observer[S <: Sys[S]] {
    def attrNumChannelsChanged(attr: AuralAttribute[S])(implicit tx: S#Tx): Unit
  }

  // ---- Factory ----

  trait Factory {
    def typeID: Int

    type Repr[~ <: Sys[~]] <: Obj[~]

    def apply[S <: SSys[S]](key: String, value: Repr[S], observer: Observer[S])
                           (implicit tx: S#Tx, context: AuralContext[S]): AuralAttribute[S]
  }

  def addFactory(f: Factory): Unit = Impl.addFactory(f)

  def factories: Iterable[Factory] = Impl.factories

  // ---- Target ----

  object Target {
    def apply[S <: SSys[S]](nodeRef: NodeRef.Full[S], key: String, targetBus: AudioBus)
                           (implicit tx: S#Tx): Target[S] = {
      val res = new impl.AuralAttributeTargetImpl[S](nodeRef, key, targetBus)
      // nodeRef.addUser(res)
      res
    }
  }

  /** An `AuralAttribute.Target` describes the mechanism by which
    * the attribute inputs can contribute their values. It is internally
    * connected to the process's node. One or multiple inputs then
    * supply their values by calling `put` and detach themselves by
    * calling `remove`. The target automatically manages summing multiple
    * inputs. While the `Value` parameter for `put` corresponds to
    * a particular attribute input, its `valueOption` gives the
    * overall signal output as sent to the node. For instance,
    * a stream input will have a bus to which is ''writes'', whereas
    * the target itself may provide a bus from this node ''reads''.
    */
  trait Target[S <: Sys[S]] extends Observable[S#Tx, Value] {
    def key: String

    def valueOption(implicit tx: S#Tx): Option[Value]

    def put   (attr: AuralAttribute[S], value: Value)(implicit tx: S#Tx): Unit
    def remove(attr: AuralAttribute[S]              )(implicit tx: S#Tx): Unit
  }

  // ---- Value ----

  object Value {
    implicit def fromFloat (value : Float     ): ScalarValue  = new ScalarValue (value )
    implicit def fromFloats(values: Vec[Float]): ScalarVector = new ScalarVector(values)
  }
  sealed trait Value { def isScalar: Boolean }
  /** Value for which a no synth is needed, but only a scalar value
    * that needs to be set on the target node.
    */
  sealed trait Scalar extends Value {
    def toControl(key: String, numChannels: Int): ControlSet
    def values: Vec[Float]
    final def isScalar = true
  }

  final case class ScalarValue(value: Float) extends Scalar {
    def toControl(key: String, numChannels: Int): ControlSet =
      if (numChannels == 1) ControlSet.Value (key, value)
      else                  ControlSet.Vector(key, Vector.fill(numChannels)(value))

    def values: Vec[Float] = Vector(value)
  }
  final case class ScalarVector(values: Vec[Float]) extends Scalar {
    def toControl(key: String, numChannels: Int): ControlSet = {
      val sz = values.size
      val xs = if (numChannels == sz) values else Vector.tabulate(numChannels)(i => values(i % sz))
      ControlSet.Vector(key, xs)
    }
  }

  /** Value for which a `Synth` is required that writes its signal to a bus,
    * and the bus is then somehow mapped to the target node's control.
    */
  final case class Stream(source: NodeRef, bus: AudioBus) extends Value {
    def isScalar = false
  }
}
trait AuralAttribute[S <: Sys[S]] extends AuralView[S, AuralAttribute.Target[S]] {
  def key: String

  def preferredNumChannels(implicit tx: S#Tx): Int

  def targetOption(implicit tx: S#Tx): Option[AuralAttribute.Target[S]]
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy