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

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

/*
 *  FileBuffer.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 java.io.RandomAccessFile
import java.nio.{ByteBuffer, DoubleBuffer}

import de.sciss.file.File

object FileBuffer {
  /** Uses the `Control` to allocate a new temporary file. */
  def apply()(implicit ctrl: Control): FileBuffer = new Impl(ctrl.createTempFile(), deleteOnDispose = true)

  def apply(file: File, deleteOnDispose: Boolean): FileBuffer = new Impl(file, deleteOnDispose = deleteOnDispose)

  private final class Impl(val file: File, deleteOnDispose: Boolean) extends FileBuffer {
    override def toString = s"FileBuffer($file)"

    private[this] val raf = new RandomAccessFile(file, "rw")
    private[this] val ch  = raf.getChannel
    private[this] var bb  = null: ByteBuffer
    private[this] var db  = null: DoubleBuffer

    def position        : Long        = ch.position() / 8
    def position_=(value: Long): Unit = ch.position(value * 8)

    def dispose(): Unit = {
      ch.close()
      if (deleteOnDispose) file.delete()
    }

    def numFrames: Long = ch.size() / 8 // raf.length() / 8

    private def ensureBuf(len: Int): Unit = {
      val lim = math.min(len, 8192)
      if (db == null || db.capacity() < lim) {
        bb = ByteBuffer.allocate(lim << 3)
        db = bb.asDoubleBuffer()
      }
    }

    def write(buf: Array[Double], off: Int, len: Int): Unit = {
      ensureBuf(len)
      var off0 = off
      var len0 = len
      while (len0 > 0) {
        val chunk = math.min(8192, len0)
        db.clear()
        db.put(buf, off0, chunk)
        bb.rewind().limit(chunk << 3)
        ch.write(bb)
        len0 -= chunk
        off0 += chunk
      }
    }

    def writeValue(value: Double, len: Int): Unit = {
      ensureBuf(len)
      val sz = math.min(len, db.capacity())
      db.clear()
      var i = 0
      while (i < sz) {
        db.put(value)
        i += 1
      }
      var len0 = len
      while (len0 > 0) {
        val chunk = math.min(8192, len0)
        bb.rewind().limit(chunk << 3)
        ch.write(bb)
        len0 -= chunk
      }
    }

    def read(buf: Array[Double], off: Int, len: Int): Unit = {
      ensureBuf(len)
      var off0 = off
      var len0 = len
      while (len0 > 0) {
        val chunk = math.min(8192, len0)
        bb.rewind().limit(chunk << 3)
        ch.read(bb)
        db.clear()
        db.get(buf, off0, chunk)
        len0 -= chunk
        off0 += chunk
      }
    }

    def rewind(): Unit = position = 0L
  }
}
/** A file buffer is similar to a monophonic 64-bit float sound file.
  * As opposed to `AudioFile`, it supports 64-bit resolution and does
  * not perform any internal caching.
  */
trait FileBuffer {
  def file: File

  var position: Long
  def numFrames: Long

  /** Same as `position = 0L`. */
  def rewind(): Unit

  def dispose(): Unit

  def read (buf: Array[Double], off: Int, len: Int): Unit
  def write(buf: Array[Double], off: Int, len: Int): Unit

  def writeValue(value: Double, len: Int): Unit
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy