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

de.sciss.fscape.graph.ComplexBinaryOp.scala Maven / Gradle / Ivy

/*
 *  ComplexBinaryOp.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 graph

import de.sciss.fscape.stream.{StreamIn, StreamOut}

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

/** Binary operator assuming operands are complex signals (real and imaginary interleaved).
  * Outputs another complex stream even if the operator yields a purely real-valued result.
  *
  * XXX TODO - need more ops such as conjugate, polar-to-cartesian, ...
  */
object ComplexBinaryOp {
  object Op {
    def apply(id: Int): Op = (id: @switch) match {
      case Plus     .id => Plus
      case Minus    .id => Minus
      case Times    .id => Times
      // case Div      .id => Div
      // case Mod      .id => Mod
//      case Eq       .id => Eq
//      case Neq      .id => Neq
//      case Difsqr   .id => Difsqr
//      case Sumsqr   .id => Sumsqr
//      case Sqrsum   .id => Sqrsum
//      case Sqrdif   .id => Sqrdif
//      case Absdif   .id => Absdif
    }
  }

  final class Complex(var re: Double, var im: Double)

  sealed trait Op {
    op =>

    def id: Int

    final def make(a: GE, b: GE): GE = new ComplexBinaryOp(op.id, a = a, b = b)

//    /** Transfers values from an input buffer
//      * to an output buffer,
//      * applying the operator.
//      *
//      * @param a        the buffer of the first operand to read from, assuming interleaved re, im data
//      * @param b        the buffer of the second operand to read from, assuming interleaved re, im data
//      * @param aOff     the index into `a`. this is a direct array index, not
//      *                 a logical index which must be multiplied by two!
//      * @param bOff     the index into `b`.
//      * @param out      the buffer to read from, assuming interleaved re, im data
//      * @param outOff   the index into `out`. this is a direct array index, not
//      *                 a logical index which must be multiplied by two!
//      * @param len      logical length of the operation, that is the number of
//      *                 complex numbers to transfer. the number of `Double` values
//      *                 read from `in` and written to `out` is twice `len`!
//      */
//    def apply(a: Array[Double], aOff: Int, b: Array[Double], bOff: Int, out: Array[Double], outOff: Int, len: Int): Unit

    def apply(aRe: Double, aIm: Double, bRe:Double, bIm: Double, out: Array[Double], outOff: Int): Unit

    def name: String = plainName.capitalize

    private def plainName: String = {
      val cn = getClass.getName
      val sz = cn.length
      val i  = cn.indexOf('$') + 1
      cn.substring(i, if (cn.charAt(sz - 1) == '$') sz - 1 else sz)
    }
  }

  case object Plus extends Op {
    final val id = 0
    override val name = "+"

//    def apply(a: Array[Double], aOff: Int, b: Array[Double], bOff: Int, out: Array[Double],
//              outOff: Int, len: Int): Unit = {
//      val aStop = aOff + (len << 1)
//      var i     = aOff
//      var j     = bOff
//      var k     = outOff
//      while (i < aStop) {
//        val aRe   = a(i); i += 1
//        val aIm   = a(i); i += 1
//        val bRe   = b(j); j += 1
//        val bIm   = b(j); j += 1
//        val outRe = aRe + bRe
//        val outIm = aIm + bIm
//        out(k) = outRe; k += 1
//        out(k) = outIm; k += 1
//      }
//    }

    def apply(aRe: Double, aIm: Double, bRe:Double, bIm: Double, out: Array[Double], outOff: Int): Unit = {
      out(outOff)     = aRe + bRe
      out(outOff + 1) = aIm + bIm
    }
  }

  case object Minus extends Op {
    final val id = 1
    override val name = "-"

//    def apply(a: Array[Double], aOff: Int, b: Array[Double], bOff: Int, out: Array[Double],
//              outOff: Int, len: Int): Unit = {
//      val aStop = aOff + (len << 1)
//      var i     = aOff
//      var j     = bOff
//      var k     = outOff
//      while (i < aStop) {
//        val aRe   = a(i); i += 1
//        val aIm   = a(i); i += 1
//        val bRe   = b(j); j += 1
//        val bIm   = b(j); j += 1
//        val outRe = aRe - bRe
//        val outIm = aIm - bIm
//        out(k) = outRe; k += 1
//        out(k) = outIm; k += 1
//      }
//    }

    def apply(aRe: Double, aIm: Double, bRe:Double, bIm: Double, out: Array[Double], outOff: Int): Unit = {
      out(outOff)     = aRe - bRe
      out(outOff + 1) = aIm - bIm
    }
  }

  case object Times extends Op {
    final val id = 2
    override val name = "*"

//    def apply(a: Array[Double], aOff: Int, b: Array[Double], bOff: Int, out: Array[Double],
//              outOff: Int, len: Int): Unit = {
//      val aStop = aOff + (len << 1)
//      var i     = aOff
//      var j     = bOff
//      var k     = outOff
//      while (i < aStop) {
//        val aRe   = a(i); i += 1
//        val aIm   = a(i); i += 1
//        val bRe   = b(j); j += 1
//        val bIm   = b(j); j += 1
//        val outRe = aRe * bRe - aIm * bIm
//        val outIm = aRe * bIm + aIm * bRe
//        out(k) = outRe; k += 1
//        out(k) = outIm; k += 1
//      }
//    }

    def apply(aRe: Double, aIm: Double, bRe:Double, bIm: Double, out: Array[Double], outOff: Int): Unit = {
      out(outOff)     = aRe * bRe - aIm * bIm
      out(outOff + 1) = aRe * bIm + aIm * bRe
    }
  }
}
final case class ComplexBinaryOp(op: Int, a: GE, b: GE) extends UGenSource.SingleOut {

  protected def makeUGens(implicit builder: UGenGraph.Builder): UGenInLike =
    unwrap(Vector(a.expand, b.expand))

  protected def makeUGen(args: Vec[UGenIn])(implicit builder: UGenGraph.Builder): UGenInLike =
    UGen.SingleOut(this, inputs = args, rest = op)

  private[fscape] def makeStream(args: Vec[StreamIn])(implicit builder: stream.Builder): StreamOut = {
    val Vec(a, b) = args
    val op0 = ComplexBinaryOp.Op(op)
    stream.ComplexBinaryOp(op = op0, a = a.toDouble, b = b.toDouble)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy