de.sciss.synth.GraphFunction.scala Maven / Gradle / Ivy
/*
* GraphFunction.scala
* (ScalaCollider)
*
* Copyright (c) 2008-2019 Hanns Holger Rutz. All rights reserved.
*
* This software is published under the GNU Lesser General Public License v2.1+
*
*
* For further information, please contact Hanns Holger Rutz at
* [email protected]
*/
package de.sciss.synth
import de.sciss.osc.{Bundle, Message}
import de.sciss.synth.ugen.WrapOut
object GraphFunction {
private[this] final var uniqueIdCnt = 0
private[this] final val uniqueSync = new AnyRef
private[this] def uniqueId(): Int = uniqueSync.synchronized {
uniqueIdCnt += 1
val result = uniqueIdCnt
result
}
object Result {
implicit def in[A](implicit view: A => GE): In[A] = In(view)
implicit case object Out extends Result[UGenSource.ZeroOut] {
def close(in: UGenSource.ZeroOut, fadeTime: Double): Unit = ()
}
implicit case object Unit extends Result[scala.Unit] {
def close(in: scala.Unit, fadeTime: Double): Unit = ()
}
final case class In[A](view: A => GE) extends Result[A] {
def close(in: A, fadeTime: Double): Unit = WrapOut(view(in), fadeTime)
}
}
sealed trait Result[-A] {
def close(in: A, fadeTime: Double): Unit
}
def mkSynthDef[A](fun: GraphFunction[A], fadeTime: Double = -1): SynthDef = {
val defName = s"temp_${uniqueId()}" // more clear than using hashCode
SynthDef(defName) {
fun.result.close(fun.peer(), fadeTime)
}
}
}
final class GraphFunction[A](val peer: () => A)(implicit val result: GraphFunction.Result[A]) {
def play(target: Node = Server.default.defaultGroup, outBus: Int = 0,
fadeTime: Double = 0.02, addAction: AddAction = addToHead): Synth = {
val server = target.server
val synthDef = GraphFunction.mkSynthDef(this, fadeTime = fadeTime)
val synth = Synth(server)
val bytes = synthDef.toBytes()
val synthMsg = synth.newMsg(synthDef.name, target, ("out" -> outBus) :: Nil, addAction)
val defFreeMsg = synthDef.freeMsg
val completion = Bundle.now(synthMsg, defFreeMsg)
if (bytes.remaining > (65535 / 4)) {
// "preliminary fix until full size works" (?)
if (server.isLocal) {
import Ops._
synthDef.load(server, completion = completion)
} else {
println("WARNING: SynthDef may have been too large to send to remote server")
server ! Message("/d_recv", bytes, completion)
}
} else {
server ! Message("/d_recv", bytes, completion)
}
synth
}
}