sciss / scalaaudiofile Contributors Wanted

Audiofile library for Scala

Version Matrix


Build Status Maven Central


ScalaAudioFile is a Scala library to read and write audio files. It is (C)opyright 2004–2018 by Hanns Holger Rutz. All rights reserved. ScalaAudioFile is released under the GNU Lesser General Public License v2.1+ and comes with absolutely no warranties. To contact the author, send an email to contact at

requirements / installation

ScalaAudioFile currently compiles against Scala 2.12, 2.11 using sbt.

To use the library in your project:

"de.sciss" %% "scalaaudiofile" % v

The current version v is "1.4.7"


Please see the file

supported formats

name read/write notes
NeXT R/W aka Snd and AU
Wave64 R/W
Raw R/W headerless

getting started

ScalaAudioFile currently supports reading and writing files, while still lacking a few features of the Java predecessor from ScissLib, such as reading and writing markers and application specific chunks.

  • To open an audio file for reading: AudioFile.openRead(aFile) or AudioFile.openRead(anInputStream). The InputStream variant has limited functionality, e.g. you cannot seek into the file, but only read sequentially. The stream variant can be used to decode files from an HTTP connection or in-memory (ByteArrayInputStream).
  • To just retrieve the specification of an existing file, to see if it can be decoded, what is length, number of channels and format are: AudioFile.readSpec(fileOrPathName).
  • To open a file for writing: AudioFile.openWrite(aFile, spec) or AudioFile.openWrite(anOutputStream, spec)

To the user, frame data is always represented as de-interleaved 32-bit floating point data, so you create a user buffer through Array.ofDim[Float](numChannels, bufFrames), or use a convenience method such as AudioFile.buffer(...).

The AudioFile implementation is currently not thread-safe, but synchronization is planned. At the moment, make sure you are not sharing an instance across threads. Alternatively, use a lock and validate the frame position before each read/write.

Here is an example of opening an existing file, reading through it to determine the maximum sample magnitude, then writing a normalized version to a new file:

    val in      = AudioFile.openRead("input.aif")
    // for the output, switch to AIFF 24-bit integer, 
    // but keep the other parameters (sample-rate and number-of-channels)
    val outSpec = in.spec.copy(fileType = AudioFileType.AIFF, 
                               sampleFormat = SampleFormat.Int24)
    val out     = AudioFile.openWrite("output.aif", outSpec)
    // create a buffer
    val bufSz   = 8192  // perform operations in blocks of this size
    val buf     = in.buffer(bufSz)

    // first pass: determine maximum magnitude
    var mag     = 0f
    var remain  = in.numFrames
    while (remain > 0) {
      val chunk = math.min(bufSz, remain).toInt, 0, chunk)
      buf.foreach { chan =>
        mag = math.max(mag, math.abs(chan.maxBy(math.abs)))
      remain -= chunk
    println(f"Maximum magnitude detected: $mag%1.3f")

    // second pass: adjust gain and write output
    require(mag > 0)
    val gain = 1f / mag // start over from the beginning of the file
    remain = in.numFrames
    while (remain > 0) {
      val chunk = math.min(bufSz, remain).toInt, 0, chunk)
      buf.foreach { chan =>
        for (i <- 0 until chunk) {
          chan(i) *= gain
      out.write(buf, 0, chunk)
      remain -= chunk


There is a system property whose value can be set to true in order to use direct-memory buffers (ByteBuffer.allocateDirect). Reading in a 1 GB is around 6% faster with direct memory. Direct memory can have the disadvantage that it requires an individual VM switch to adjust the maximum available memory before throwing an out-of-memory error. The default is false.

For all further information, please refer to the API docs. They can be created with sbt doc.