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

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

/*
 *  Code.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.event.Targets
import de.sciss.lucre.expr
import de.sciss.lucre.expr.impl.ExprTypeImpl
import de.sciss.lucre.stm.Sys
import de.sciss.processor.ProcessorLike
import de.sciss.serial.{DataInput, DataOutput, ImmutableSerializer, Writable}
import de.sciss.synth
import de.sciss.synth.proc.impl.{CodeImpl => Impl}

import scala.annotation.switch
import scala.collection.immutable.{IndexedSeq => Vec}
import scala.concurrent.{ExecutionContext, Future, blocking}

object Code {
  final val typeID = 0x20001

  def init(): Unit = Obj.init()

  final val UserPackage = "user"

  final case class CompilationFailed() extends Exception
  final case class CodeIncomplete   () extends Exception

  implicit def serializer: ImmutableSerializer[Code] = Impl.serializer

  def read(in: DataInput): Code = serializer.read(in)

  def apply(id: Int, source: String): Code = (id: @switch) match {
    case FileTransform.id => FileTransform(source)
    case SynthGraph   .id => SynthGraph   (source)
    case Action       .id => Action       (source)
  }

  def future[A](fun: => A)(implicit compiler: Code.Compiler): Future[A] = Impl.future(fun)

  def registerImports(id: Int, imports: Seq[String]): Unit = Impl.registerImports(id, imports)

  def getImports(id: Int): Vec[String] = Impl.getImports(id)

  // ---- compiler ----

  def unpackJar(bytes: Array[Byte]): Map[String, Array[Byte]] = Impl.unpackJar(bytes)

  trait Compiler {
    implicit def executionContext: ExecutionContext

    /** Synchronous call to cmpile a source code consisting of a body which is wrapped in a `Function0` apply method,
      * returning the raw jar file produced in the compilation.
      *
      * May throw `CompilationFailed` or `CodeIncomplete`
      *
      * @param  source  the completely formatted source code to compile which should contain
      *                 a proper package and class definition. It must contain any
      *                 necessary `import` statements.
      * @return the jar file as byte-array, containing the opaque contents of the source code
      *         (possible the one single class defined)
      */
    def compile(source: String): Array[Byte]

    /** Synchronous call to compile and execute the provided source code.
      *
      * May throw `CompilationFailed` or `CodeIncomplete`
      *
      * @param  source  the completely formatted source code to compile which forms the body
      *                 of an imported object. It must contain any necessary `import` statements.
      * @return the evaluation result, or `()` if there is no result value
      */
    def interpret(source: String, execute: Boolean): Any
  }

  // ---- type: FileTransform ----

  object FileTransform {
    final val id    = 0
    final val name  = "File Transform"
  }
  final case class FileTransform(source: String) extends Code {
    type In     = (File, File, ProcessorLike[Any, Any] => Unit)
    type Out    = Future[Unit]
    def id      = FileTransform.id

    def compileBody()(implicit compiler: Code.Compiler): Future[Unit] = Impl.compileBody[In, Out, FileTransform](this)

    def execute(in: In)(implicit compiler: Code.Compiler): Out = Impl.execute[In, Out, FileTransform](this, in)

    def contextName = FileTransform.name

    def updateSource(newText: String) = copy(source = newText)
  }

  // ---- type: SynthGraph ----

  object SynthGraph {
    final val id    = 1
    final val name  = "Synth Graph"
  }
  final case class SynthGraph(source: String) extends Code {
    type In     = Unit
    type Out    = synth.SynthGraph
    def id      = SynthGraph.id

    def compileBody()(implicit compiler: Code.Compiler): Future[Unit] = Impl.compileBody[In, Out, SynthGraph](this)

    def execute(in: In)(implicit compiler: Code.Compiler): Out = Impl.execute[In, Out, SynthGraph](this, in)

    def contextName = SynthGraph.name

    def updateSource(newText: String) = copy(source = newText)
  }

  // ---- type: Action ----

  object Action {
    final val id    = 2
    final val name  = "Action"
  }
  final case class Action(source: String) extends Code {
    type In     = String
    type Out    = Array[Byte]
    def id      = Action.id

    def compileBody()(implicit compiler: Code.Compiler): Future[Unit] = future(blocking { execute("Unnamed"); () })

    def execute(in: In)(implicit compiler: Code.Compiler): Out = {
      // Impl.execute[In, Out, Action](this, in)
      Impl.compileToFunction(in, this)
    }

    def contextName = Action.name

    def updateSource(newText: String) = copy(source = newText)

    // def compileToFunction(name: String): Future[Array[Byte]] = Impl.compileToFunction(name, this)
  }

  // ---- expr ----

  object Obj extends ExprTypeImpl[Code, Obj] {
    import Code.{Obj => Repr}

    def typeID = Code.typeID

    def valueSerializer: ImmutableSerializer[Code] = Code.serializer

    protected def mkConst[S <: Sys[S]](id: S#ID, value: A)(implicit tx: S#Tx): Const[S] =
      new _Const[S](id, value)

    protected def mkVar[S <: Sys[S]](targets: Targets[S], vr: S#Var[Ex[S]], connect: Boolean)(implicit tx: S#Tx): Var[S] = {
      val res = new _Var[S](targets, vr)
      if (connect) res.connect()
      res
    }

    private final class _Const[S <: Sys[S]](val id: S#ID, val constValue: A)
      extends ConstImpl[S] with Repr[S]

    private final class _Var[S <: Sys[S]](val targets: Targets[S], val ref: S#Var[Ex[S]])
      extends VarImpl[S] with Repr[S]
  }
  trait Obj[S <: Sys[S]] extends expr.Expr[S, Code]
}
sealed trait Code extends Writable { me =>
  type Self = Code { type In = me.In; type Out = me.Out }

  /** The interfacing input type */
  type In
  /** The interfacing output type */
  type Out

  /** Identifier to distinguish types of code. */
  def id: Int

  /** Source code. */
  def source: String

  def updateSource(newText: String): Self

  /** Human readable name. */
  def contextName: String

  /** Compiles the code body without executing it. */
  def compileBody()(implicit compiler: Code.Compiler): Future[Unit]

  /** Compiles and executes the code. Returns the wrapped result. */
  def execute(in: In)(implicit compiler: Code.Compiler): Out // = compile()(in)

  def write(out: DataOutput): Unit = Code.serializer.write(this, out)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy