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

de.sciss.fscape.stream.StreamIn.scala Maven / Gradle / Ivy

/*
 *  StreamIn.scala
 *  (FScape)
 *
 *  Copyright (c) 2001-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.fscape
package stream

import akka.stream.Outlet
import akka.stream.scaladsl.{GraphDSL, Sink}

import scala.annotation.switch
import scala.collection.immutable.{IndexedSeq => Vec}
import scala.language.implicitConversions

object StreamIn {
  def singleD(peer: OutD): StreamIn = new SingleD(peer)
  def singleI(peer: OutI): StreamIn = new SingleI(peer)
  def singleL(peer: OutL): StreamIn = new SingleL(peer)

  def multiD(peer: OutD, numSinks: Int): StreamIn = new MultiD(peer, numSinks)
  def multiI(peer: OutI, numSinks: Int): StreamIn = new MultiI(peer, numSinks)
  def multiL(peer: OutL, numSinks: Int): StreamIn = new MultiL(peer, numSinks)

  object unused extends StreamIn {
    def toAny   (implicit b: Builder): Outlet[BufLike] = throw new UnsupportedOperationException("StreamIn.unused.toAny")
    def toDouble(implicit b: Builder): OutD = throw new UnsupportedOperationException("StreamIn.unused.toDouble")
    def toInt   (implicit b: Builder): OutI = throw new UnsupportedOperationException("StreamIn.unused.toInt"   )
    def toLong  (implicit b: Builder): OutL = throw new UnsupportedOperationException("StreamIn.unused.toLong"  )

    def isInt   : Boolean = false
    def isLong  : Boolean = false
    def isDouble: Boolean = true    // arbitrary
  }

  private final class SingleD(peer: OutD) extends StreamIn {
    private[this] var exhausted = false

    def isInt   : Boolean = false
    def isLong  : Boolean = false
    def isDouble: Boolean = true

    def toAny(implicit b: Builder): Outlet[BufLike] = toDouble.as[BufLike]  // retarded Akka API. Why is Outlet not covariant?

    def toDouble(implicit b: Builder): OutD = {
      require(!exhausted)
      exhausted = true
      peer
    }

    def toInt(implicit builder: Builder): OutI = {
      require(!exhausted)
      exhausted = true
      val ctrl = builder.control
      builder.map(peer) { bufD =>
        val bufI = ctrl.borrowBufI()
        val sz = bufD.size
        bufI.size = sz
        val a = bufD.buf
        val b = bufI.buf
        var i = 0
        while (i < sz) {
          val x = a(i)
          b(i)  = math.max(Int.MinValue, math.min(Int.MaxValue, math.round(x))).toInt
          i += 1
        }
        bufD.release()
        bufI
      }
    }

    def toLong(implicit builder: Builder): OutL = {
      require(!exhausted)
      exhausted = true
      val ctrl = builder.control
      builder.map(peer) { bufD =>
        val bufL = ctrl.borrowBufL()
        val sz = bufD.size
        bufL.size = sz
        val a = bufD.buf
        val b = bufL.buf
        var i = 0
        while (i < sz) {
          val x = a(i)
          b(i) = math.round(x)
          i += 1
        }
        bufD.release()
        bufL
      }
    }
  }

  private final class SingleI(peer: OutI) extends StreamIn {
    private[this] var exhausted = false

    def isInt   : Boolean = true
    def isLong  : Boolean = false
    def isDouble: Boolean = false

    def toAny(implicit b: Builder): Outlet[BufLike] = toInt.as[BufLike]

    def toInt(implicit b: Builder): OutI = {
      require(!exhausted)
      exhausted = true
      peer
    }

    def toLong(implicit builder: Builder): OutL = {
      require(!exhausted)
      exhausted = true
      val ctrl = builder.control
      builder.map(peer) { bufI =>
        val bufL = ctrl.borrowBufL()
        val sz = bufI.size
        bufL.size = sz
        val a = bufI.buf
        val b = bufL.buf
        var i = 0
        while (i < sz) {
          val x = a(i)
          b(i)  = x.toLong
          i += 1
        }
        bufI.release()
        bufL
      }
    }

    def toDouble(implicit builder: Builder): OutD = {
      require(!exhausted)
      exhausted = true
      val ctrl = builder.control
      builder.map(peer) { bufI =>
        val bufD = ctrl.borrowBufD()
        val sz = bufI.size
        bufD.size = sz
        val a = bufI.buf
        val b = bufD.buf
        var i = 0
        while (i < sz) {
          val x = a(i)
          b(i) = x.toDouble
          i += 1
        }
        bufI.release()
        bufD
      }
    }
  }

  private final class SingleL(peer: OutL) extends StreamIn {
    private[this] var exhausted = false

    def isInt   : Boolean = false
    def isLong  : Boolean = true
    def isDouble: Boolean = false

    def toAny(implicit b: Builder): Outlet[BufLike] = toLong.as[BufLike]

    def toLong(implicit b: Builder): OutL = {
      require(!exhausted)
      exhausted = true
      peer
    }

    def toInt(implicit builder: Builder): OutI = {
      require(!exhausted)
      exhausted = true
      val ctrl = builder.control
      builder.map(peer) { bufL =>
        val bufI = ctrl.borrowBufI()
        val sz = bufL.size
        bufI.size = sz
        val a = bufL.buf
        val b = bufI.buf
        var i = 0
        while (i < sz) {
          val x = a(i)
          b(i)  = math.max(Int.MinValue, math.min(Int.MaxValue, x)).toInt
          i += 1
        }
        bufL.release()
        bufI
      }
    }

    def toDouble(implicit builder: Builder): OutD = {
      require(!exhausted)
      exhausted = true
      val ctrl = builder.control
      builder.map(peer) { bufL =>
        val bufD = ctrl.borrowBufD()
        val sz = bufL.size
        bufD.size = sz
        val a = bufL.buf
        val b = bufD.buf
        var i = 0
        while (i < sz) {
          val x = a(i)
          b(i) = x.toDouble
          i += 1
        }
        bufL.release()
        bufD
      }
    }
  }

  private final class MultiD(peer: OutD, numSinks: Int) extends StreamIn {
    private[this] var remain = numSinks
    private[this] var broad: Vec[OutD] = _ // create lazily because we need stream.Builder

    def isInt   : Boolean = false
    def isLong  : Boolean = false
    def isDouble: Boolean = true

    private def alloc()(implicit b: Builder): OutD = {
      require(remain > 0)
      if (broad == null) broad = BroadcastBuf(peer, numSinks)
      remain -= 1
      val head +: tail = broad
      broad = tail
      head
    }

    def toAny   (implicit b: Builder): Outlet[BufLike] = toDouble.as[BufLike]
    def toDouble(implicit b: Builder): OutD = alloc()
    def toInt   (implicit b: Builder): OutI = singleD(alloc()).toInt   // just reuse this functionality
    def toLong  (implicit b: Builder): OutL = singleD(alloc()).toLong  // just reuse this functionality
  }

  private final class MultiI(peer: OutI, numSinks: Int) extends StreamIn {
    private[this] var remain = numSinks
    private[this] var broad: Vec[OutI] = _ // create lazily because we need stream.Builder

    def isInt   : Boolean = true
    def isLong  : Boolean = false
    def isDouble: Boolean = false

    private def alloc()(implicit b: Builder): OutI = {
      require(remain > 0)
      if (broad == null) broad = BroadcastBuf(peer, numSinks)
      remain -= 1
      val head +: tail = broad
      broad = tail
      head
    }

    def toAny   (implicit b: Builder): Outlet[BufLike] = toLong.as[BufLike]
    def toDouble(implicit b: Builder): OutD = singleI(alloc()).toDouble   // just reuse this functionality
    def toInt   (implicit b: Builder): OutI = alloc()
    def toLong  (implicit b: Builder): OutL = singleI(alloc()).toLong     // just reuse this functionality
  }

  private final class MultiL(peer: OutL, numSinks: Int) extends StreamIn {
    private[this] var remain = numSinks
    private[this] var broad: Vec[OutL] = _ // create lazily because we need stream.Builder

    def isInt   : Boolean = false
    def isLong  : Boolean = true
    def isDouble: Boolean = false

    private def alloc()(implicit b: Builder): OutL = {
      require(remain > 0)
      if (broad == null) broad = BroadcastBuf(peer, numSinks)
      remain -= 1
      val head +: tail = broad
      broad = tail
      head
    }

    def toAny   (implicit b: Builder): Outlet[BufLike] = toLong.as[BufLike]
    def toDouble(implicit b: Builder): OutD = singleL(alloc()).toDouble  // just reuse this functionality
    def toInt   (implicit b: Builder): OutI = singleL(alloc()).toInt     // just reuse this functionality
    def toLong  (implicit b: Builder): OutL = alloc()
  }
}
trait StreamIn {
  def toDouble(implicit b: Builder): OutD
  def toInt   (implicit b: Builder): OutI
  def toLong  (implicit b: Builder): OutL
  def toAny   (implicit b: Builder): Outlet[BufLike]

  def isInt   : Boolean
  def isLong  : Boolean
  def isDouble: Boolean
}

object StreamOut {
  implicit def fromDouble   (peer:     OutD ):     StreamOut  = new StreamOutD(peer)
  implicit def fromDoubleVec(peer: Vec[OutD]): Vec[StreamOut] = peer.map(new StreamOutD(_))
  implicit def fromInt      (peer:     OutI ):     StreamOut  = new StreamOutI(peer)
  implicit def fromLong     (peer:     OutL ):     StreamOut  = new StreamOutL(peer)

  private final class StreamOutD(peer: OutD) extends StreamOut {
    override def toString = s"StreamOut($peer)"

    def toIn(numChildren: Int)(implicit b: stream.Builder): StreamIn = (numChildren: @switch) match {
      case 0 =>
        implicit val dsl = b.dsl
        import GraphDSL.Implicits._
        peer ~> Sink.ignore
        StreamIn.unused
      case 1 => StreamIn.singleD(peer)
      case n => StreamIn.multiD (peer, numChildren)
    }
  }

  private final class StreamOutI(peer: OutI) extends StreamOut {
    override def toString = s"StreamOut($peer)"

    def toIn(numChildren: Int)(implicit b: stream.Builder): StreamIn = (numChildren: @switch) match {
      case 0 =>
        implicit val dsl = b.dsl
        import GraphDSL.Implicits._
        peer ~> Sink.ignore
        StreamIn.unused
      case 1 => StreamIn.singleI(peer)
      case n => StreamIn.multiI (peer, numChildren)
    }
  }

  private final class StreamOutL(peer: OutL) extends StreamOut {
    override def toString = s"StreamOut($peer)"

    def toIn(numChildren: Int)(implicit b: stream.Builder): StreamIn = (numChildren: @switch) match {
      case 0 =>
        implicit val dsl = b.dsl
        import GraphDSL.Implicits._
        peer ~> Sink.ignore
        StreamIn.unused
      case 1 => StreamIn.singleL(peer)
      case n => StreamIn.multiL (peer, numChildren)
    }
  }
}
trait StreamOut {
  def toIn(numChildren: Int)(implicit b: stream.Builder): StreamIn
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy