Skip to content

Latest commit

 

History

History
301 lines (201 loc) · 7.14 KB

README.md

File metadata and controls

301 lines (201 loc) · 7.14 KB

interchange-file-format

A module for working with Interchange File Format (IFF) data.

Installation

$ npm install interchange-file-format

Example

The following example implements a few structures for the AIFF (Audio Interchange File Format)

const { Form, Chunk, extensions } = require('interchange-file-format')
const fs = require('fs')

extensions.set('COMM', class CommonChunk extends Chunk {
  get numChannels() { return this.readUIntBE(0, 2) }
  get numSampleFrames() { return this.readUIntBE(2, 4) }
  get sampleSize() { return this.readUIntBE(6, 2) }
  get sampleRate() {
    const x = this.readUIntBE(8, 2)
    const y = this.readUIntBE(10, 1)
    const z = this.readUIntBE(11, 1)
    const pre = 16398
    const pad = x - pre
    const shifted = (y << 8) + z
    return shifted << pad
  }
})

extensions.set('SSND', class SoundDataChunk extends Chunk {
  get offset() { return this.readUIntBE(0, 4) }
  get blockSize() { return this.readUIntBE(4, 4) }
  get soundData() { return this.slice(8) }
})

const stream = fs.createReadStream('/path/to/audio/track.aif')
const form = new Form({ type: 'AIFF' })

stream.pipe(form.createWriteStream()).on('finish', () => {
  for (const chunk of form) {
    // `chunk` could be `CommonChunk` or `SoundDataChunk` when `COMM`
    // and `SSND` chunk IDs are foud
    console.log(chunk)
  }
})

API

ID

The ID class represents a container for 32 bits of characters, the concatenation of four printable ASCII character in the range ' ' (SP, 0x20) through '~' (0x7E). Spaces (0x20) cannot precede printing characters; trailing spaces are allowed. Control characters are forbidden.

The ID class extends Uint8Array and is polymorphic with the Buffer API.

id = ID.from(bufferOrString)

Creates a 4 byte ID instance from a Buffer or string. A Chunk can be identified by an ID. A Form will use an ID to describe its type.

const id = ID.from('FORM')
validated = id.set(bytes)

Set id value bytes on ID instance.

if (!id.set(bytesOrString)) {
  // bytes invalid or too large
}
buffer = id.toBuffer()

Convert ID instance directly to Buffer, using the same internal ArrayBuffer for this instance.

const buffer = id.toBuffer()

Chunk

The Chunk class is a container for bytes with a known ID and size. A Chunk can be manually constructed or derived from an existing buffer (see Chunk.from()).

chunk = new Chunk(id, options)

Create a new Chunk instance from ID with options where options can be:

{
  size: required, // size in bytes of chunk body
  ancestor: null  // the ancestor this chunk is derived from
}
const chunk = new Chunk('FORM', { size: 32 }) // 32 byte chunk body
chunk.set(bytes) // set bytes on chunk

chunk = Chunk.from(buffer, options)

Create a new Chunk from a given buffer with constructor options.

const chunk = Chunk.from(bufferFromSource)
chunk.data

A Buffer pointer to the Chunk data.

chunk.set(bytes[, offset])

Set bytes or a string on Chunk.

chunk = chunk.map(map)

Map over the chunks in this chunk returning a new Chunk instance.

chunk = chunk.filter(filter)

Filter over the chunks in this chunk returning a new Chunk instance.

chunk = chunk.slice(start[, stop])

Creates a new Chunk instance as a slice from this instance.

array = chunk.toArray()

Convert Chunk into an Array.

buffer = chunk.toBuffer()

Converts (serializes) the Chunk to a Buffer, including the ID and size bytes as header values.

ChunkIterator

A Chunk iterator that implements the Iterator Protocol and satisfies the Iterable interface requirements.

iterator = ChunkIterator.from(buffer[, offset])

Creates a new ChunkIterator from a given buffer starting at an optional offset.

const iterator = ChunkIterator.from(bufferSource)
for (const chunk of iterator) {
  console.log('%s', chunk.id, chunk)
}

Group

An abstract class that extends Array that behaves like a container that for many things. Classes like Form and List extend this type for the FORM and LIST chunk types, respectively.

group = new Group(id, options)

Creates a new Group from a given ID with options where option can be:

{
  type: required, // A string type name for the group, this could be the
                  // FORM type, or the record type for a LIST
}
const group = new Group('FORM', { type: 'TEST' })

group = Group.from(buffer)

Creates a new Group instance from a given buffer, loading types and extensions based on parsed chunk IDs.

const form = Group.from(bufferSource) // `bufferSource` could be a AIFF file on disk
group.chunks

A concatenated buffer of all chunks in this group.

group.append(chunks)

Append a chunk or an array of chunks to the group, setting this instance as the chunks ancestor.

group.push(...chunks)

Pushes a new Chunk into the group, setting this instance as the chunks ancestor.

group.unshift(...chunks)

"Unshifts" or left pushes a new Chunk into the group, setting this instance as the chunks ancestor.

chunk = group.shift()

Shift a chunk out of the group, removing a reference to this instance as the ancestor.

chunk = group.pop()

Pop a chunk out of the group, removing a reference to this instance as the ancestor.

group = group.concat(...chunks)

Concatenates and returns a new Group instance with given chunks (or Group).

group = group.map(map)

Map over the chunks in this group returning a new Group instance.

group = group.filter(filter)

Filter over the chunks in this group returning a new Group instance.

group = group.slice(start[, stop])

Creates a new Group instance as a slice from this instance.

array = group.toArray()

Convert this instance into an Array.

buffer = group.toBuffer()

Creates a buffer from this Group instance flattening all chunks in the hierarchy.

stream = group.createReadStream()

Get a ReadStream for chunks in a Group instance.

stream = group.createWriteStream()

Get a WriteStream for writing chunks in a Group instance.

Form

A Group type with an ID set to FORM.

List

A Group type with an ID set to LIST.

CAT

A special Group type with an ID set to LIST with a restriction on the types of descendants being only other Group types.

extensions

A static Map of Group extensions that map a 4 byte chunk ID string to a class that extends Group or Chunk to handle extensions to the EA IFF 85 spec, such as AIFF (or AIFC) with the NAME or SSND types.

const { Chunk, Group, extensions } = require('interchange-file-format')
class TextChunk extends Chunk {
  get text() {
    return this.slice(0, this.size).toString()
  }
}

// when then `NAME` or `AUTH` chunk ID is seen in a `Group`, this class will be used
extensions.set('NAME', TextChunk)
extensions.set('AUTH', TextChunk)

License

MIT