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

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

/*
 *  Bounce.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 java.io.File

import de.sciss.lucre.stm
import de.sciss.lucre.stm.Obj
import de.sciss.lucre.synth.{Server, Sys}
import de.sciss.processor.ProcessorFactory
import de.sciss.span.Span
import de.sciss.synth.proc.impl.{BounceImpl => Impl}

import scala.collection.immutable.{Iterable => IIterable}
import scala.language.implicitConversions

object Bounce {
  def apply[S <: Sys[S], I <: stm.Sys[I]](implicit cursor: stm.Cursor[S], bridge: S#Tx => I#Tx,
                                          workspace: WorkspaceHandle[S]): Bounce[S] =
    new Impl[S, I]

  private type GroupH[S <: Sys[S]] = IIterable[stm.Source[S#Tx, Obj[S]]]

  sealed trait ConfigLike[S <: Sys[S]] {
    /** The group to transport through the bounce.
      * This parameter is initially unspecified in the builder, and calling the getter will throw an error.
      * This parameter must be specified before generating a `Config` instance.
      */
    def group: GroupH[S]

    /** The span of the timeline to bounce. */
    def span: Span

    /** Configuration of the offline server.
      * It is crucial to specify the NRT bits, i.e.
      * `nrtInputPath` (if used), `nrtOutputPath`,
      * `nrtHeaderFormat` (defaults to AIFF), `nrtSampleFormat` (defaults to Float32),
      * as well as the number of input and output channels
      * `inputBusChannels` and `outputBusChannels`, and finally
      * the sampling rate `sampleRate`.
      *
      * Typically you will not specify the `nrtCommandPath` (NRT OSC file). For debugging purposes this
      * may be set, otherwise a temporary file is automatically generated.
      */
    def server: Server.ConfigLike

    /** An arbitrary function may be provided which is called when the server is initialized (logical time zero).
      * This entry is typically used to set up extra routing synths, master volume, etc.
      */
    def beforePrepare: (S#Tx, Server) => Unit
    def beforePlay   : (S#Tx, Server) => Unit

    /** Whether to run the server in real-time or offline. */
    def realtime: Boolean
  }
  object Config {
    val NoOp = (_: Any, _: Any) => ()

    def apply[S <: Sys[S]]: ConfigBuilder[S] = new ConfigBuilder

    implicit def build[S <: Sys[S]](b: ConfigBuilder[S]): Config[S] = b.build
  }
  sealed trait Config[S <: Sys[S]] extends ConfigLike[S] {
    def server: Server.Config
  }
  final class ConfigBuilder[S <: Sys[S]] private[Bounce] () extends ConfigLike[S] {
    private var _group: GroupH[S] = null
    def group: GroupH[S] = {
      if (_group == null) throw new IllegalStateException("A group has not yet been assigned")
      _group
    }
    def group_=(value: GroupH[S]): Unit = _group = value

    /** The default span is from zero to one second. */
    var span  : Span                    = Span(0L, TimeRef.SampleRate.toLong)
    /** The default server configuration is ScalaCollider's
      * default, a block-size of one, no input and one output channel.
      */
    val server: Server.ConfigBuilder    = Server.Config()

    var beforePrepare: (S#Tx, Server) => Unit  = Config.NoOp
    var beforePlay   : (S#Tx, Server) => Unit  = Config.NoOp

    /** The default mode is offline (realtime == `false`) */
    var realtime: Boolean = false

    // some sensible defaults
    server.blockSize          = 1
    server.inputBusChannels   = 0
    server.outputBusChannels  = 1

    def build: Config[S] = ConfigImpl(group = group, span = span, server = server,
      beforePrepare = beforePrepare, beforePlay = beforePlay, realtime = realtime)
  }

  private final case class ConfigImpl[S <: Sys[S]](group: GroupH[S], span: Span, server: Server.Config,
                                                   beforePrepare: (S#Tx, Server) => Unit,
                                                   beforePlay   : (S#Tx, Server) => Unit, realtime: Boolean)
    extends Config[S] {

    override def productPrefix = "Config"
  }

  final case class ServerFailed(code: Int) extends Exception {
    override def toString = s"$productPrefix($code)"
  }
}
trait Bounce[S <: Sys[S]] extends ProcessorFactory {
  type Product  = File
  type Config   = Bounce.Config[S]
  type Repr     = Generic
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy