# LibAiff Reference Manual

#### LibAiff 5.0, $Revision: 1.16.2.2 $

## Contents

1. About LibAiff
2. About Audio IFF
3. How digital audio is stored on Audio IFF files
4. Using LibAiff
5. Referencing to Audio IFF files
6. Opening and closing an Audio IFF file
7. Attributes
8. Getting and setting the sound format
9. Reading sound samples: the raw mode
10. Reading sound samples: the normal mode
11. Seeking
12. Writing sound data
13. Markers
14. Instrument data

## 1. About LibAiff

LibAiff is a library for C applications, providing transparent read & write operations for Audio Interchange File Format files.

With LibAiff your application can easily use the Audio IFF format to interchange digital audio.

LibAiff wants to implement all the features of the AIFF 1.3 standard, including markers, comments, etc.

### The LibAiff 5.0 version

This version of LibAiff supports the following features:

- Reading any valid Audio IFF file.
- Writing a valid Audio IFF or AIFF Compressed (AIFC) file.
- Reading a compressed AIFF Compressed (AIFC) file with audio encoded in the following formats:
  - Linear PCM (both big-endian and little-endian)
  - µ-Law (u-Law)
  - A-Law
  - 32-bit IEEE-754 floating point (float32)
- Read & write samples in all formats supported by the Audio IFF standard.
- Transparently receiving samples in 32-bit LPCM or floating-point PCM, with LibAiff doing all the conversions (if necessary).
- Transparently writing 32-bit LPCM audio, with LibAiff doing all the conversions (if necessary).
- Getting and setting all the AIFF Attributes.
- Reading and writing markers to positions on the sound.
- Reading instrument data from AIFF files.

## 2. About Audio IFF

Audio Interchange File Format (Audio IFF or simply AIFF) is a flexible file standard for storing and interchanging digital audio, used by Apple and Silicon Graphics, and designed to facilitate the sharing of sound data between applications.

According to the official specification, Audio IFF is the result of several meetings held with music developers over a period of ten months in 1987-88.

## 3. How digital audio is stored on Audio IFF files

### Encodings supported by LibAiff

LibAiff supports both linear encodings and logarithmic encodings when reading AIFF or AIFF-C files. However, the only format supported for writing is Linear PCM, the standard audio signal encoding.

Linear encodings divide the given voltage range in equidistant steps or quants. As a result, loud signals (multiplicative) are encoded with more precision than weak signals (which have more rounding error in the quantization to steps of the same difference than the multiplicative signals).

LibAiff supports the following linear encodings:

- Linear PCM (LPCM), both big-endian and little-endian. Any bitwidth from 8 bits to 32 bits is supported.

Logarithmic encodings or floating point encodings have more quantization points in the low level range than in the high level range. As a result, loud signals (multiplicative) and weak signals are given the same resolution. When compared to linear encodings, logarithmic encodings provide better resolution than linear ones for low signals but worse resolution for loud signals.

LibAiff supports the following logarithmic encodings:

- 8-bit µ-Law
- 8-bit A-Law
- 32-bit IEEE-754 floating point (float32)

A 8-bit µ-Law encoding is equivalent to a 14-bit LPCM encoding for low signals, and equivalent to a 6-bit LPCM encoding for loud signals. Thus, it's a lossy encoding when compared to a full 14-bit LPCM, but provides a 2:1 size ratio (since 14-bit LPCM is packed into 2-byte segments) while retaining the same resolution for low signals, which can be used for compression purposes. It can efficiently compress signals which are statistically more likely to be near a low level than a high signal level.

As detailed before, LibAiff can do any conversions automatically, so any logarithmic encoded data will be transparently handled and converted by the library, so the application only needs to handle Linear PCM data (or floating-point PCM data if the application prefers that). µ-Law encodings are converted to full 14-bit LPCM data (lossless conversion), and A-Law encodings are converted to 13-bit LPCM.

32-bit IEEE-754 floating point can be converted to 32-bit integer LPCM. Note that this conversion loses some extra precision present on the original floating point values, due to the differences between linear and logarithmic encodings detailed above. Reading these samples in floating-point mode is a lossless operation.

### How Linear PCM is handled by AIFF and LibAiff

LPCM audio is stored as sample points, which are samples taken of the sound wave. Each sample point is a signed value quantized to a fixed number of bits (the bitwidth or sample size). Of course, increasing the sample size will increase the resolution or definition of the sound wave, resulting in a greater sound quality.

Audio IFF supports sample sizes from 8 to 32 bits per sample.

Sample points are aligned into byte-oriented segments. The size of the segments in bytes is the segment size. Audio IFF supports segment sizes from 1 to 4 bytes.

Segments are used to make dealing with sample points easier, since most CPU's are byte-oriented. This means, in example, that 13-bit sample points are aligned into 2-byte segments.

Sample size | Segment size
--- | ---
8 bits | 1 byte
9 to 16 bits | 2 bytes
17 to 24 bits | 3 bytes
25 to 32 bits | 4 bytes

Sample points are left-justified inside a segment:

     ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___
    |   |	|   |   |   |	|   |   |   |   |   |   |   |   |   |   |
    | 1   0   1   0   0   0   0   1   0   1   1   0   1   0   0   0 |
    |___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|
     <-------------------------------------------------> <--------->
                  13-bit sample point                      Padding
     <------------------------------------------------------------->
                               2-byte segment

An audio file may contain more than one channel of sound. This is used, in example, in stereo, surround and quadraphonic speaker-arrangements.

Each channel has its own independent sample points and segments.

Channel segments that are meant to be played simultaneously are packed together into a sample frame. In example, in a 2-channel stereo file, each sample frame contains 2 segments, one for each channel.

     ___________ ___________ ___________ ___________
    |           |           |           |           |
    | Channel 1 | Channel 2 | Channel 1 | Channel 2 |
    |___________|___________|___________|___________|
     <---------> <---------> <---------> <--------->
       Segment     Segment     Segment     Segment
     <---------------------> <--------------------->
         Sample frame 1          Sample frame 2

All of the segments packed in a sample frame correspond to the same time on the sound.

The number of sample frames per second taken of a sound wave is called the sampling rate. Audio IFF supports virtually any sampling rate, being this limited by your playing/recording software or hardware.

The most used sampling rates are: 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 88200 and 96000 sample frames per second.

Increasing the sampling rate will result in a greater sound quality.

Also, modifying the sampling rate without modifying the samples will alter the sound speed and pitch.

## 4. Using LibAiff

The first step to use the LibAiff in your C application, is to include the LibAiff header file (you need to have LibAiff installed or accessible from your development environment):

    #define LIBAIFF_NOCOMPAT 1 // do not use LibAiff 2 API compatibility
    #include <libaiff/libaiff.h>

The <libaiff.h> file has the type definitions and function prototypes of LibAiff.

When compiling your application, you need to link it with LibAiff. In example, using the command-line C compiler on a UNIX operating system:

    % cc obj1.o obj2.o obj3.o -lm -laiff -o binary

(The `-lm` modifier is to link with the math library, used by LibAiff and perhaps by your application too).

## 5. Referencing to Audio IFF files

References are an abstract form of representing Audio IFF files used for reading & writing operations inside LibAiff.

You pass these references as an argument to the LibAiff functions.

The library uses the following C data type to refer to Audio IFF files:

    AIFF_Ref  file;

## 6. Opening and closing an Audio IFF file

    /*
     * 'name' is a relative or absolute path
     * to a file.
     */
    AIFF_Ref AIFF_OpenFile(const char* name, int flags) ;

`name` is the name (or path) of the file to open. `flags` are a combination of ORed binary flags which can be:

- `F_RDONLY`: Open the file for reading.
- `F_WRONLY`: Open the file for writing.
- `F_NOTSEEKABLE`: The input file is not seekable (for example, a UNIX pipe). This is for files opened for reading.
- `F_AIFC`: Write always AIFF-C files instead of normal AIFF files.
- `F_OPTIMIZE`: Write optimized AIFF-C files (this implies the `F_AIFC` option). Optimized means that the file will be written in native endianness, to avoid any CPU-consuming byte-swappings.

You use the above function to open an Audio IFF file for reading or writing.

The function will return a reference (see section 5) or `NULL` if the file cannot be opened (i.e, the file does not exist or it cannot be created).

Since the function uses dynamic memory, you can open more than one Audio IFF file at the same time.

When you have finished working with an Audio IFF file you should close it:

    int AIFF_CloseFile(AIFF_Ref r) ;

In case of writing, you need to close it when finished to construct a valid Audio IFF. If your program finish without closing the file, it will be incomplete.

Sample code:

    AIFF_Ref ref ;

    ref = AIFF_OpenFile("../Music/track05.aiff", F_RDONLY) ;
    if( ref )
    {
    	puts("File opened successfully.") ;
    	AIFF_Close(ref);
    }

## 7. Attributes

Attributes are metadata stored into an Audio IFF file, which helps to identify the content of the file (like the name of the musical piece, its author or composer, its copyright and licensing, and some annotations).

The available attribute identifiers are defined on the LibAiff header file.

The following attributes can be used on Audio IFF files:

- Name (`AIFF_NAME`)
- Author (`AIFF_AUTH`)
- Copyright (`AIFF_COPY`)
- Annotations (`AIFF_ANNO`)

### Reading attributes

To extract an attribute from a reading Audio IFF file:

    char* AIFF_GetAttribute(AIFF_Ref r,IFFType typ) ;

`IFFType` should be a valid identifier of an attribute (see the list above).

The function will return a valid nul-terminated C-string if the attribute is present on the file, or `NULL` if it isn`t.

You should free the resulting pointer when you have finished using it.

Sample code:

    char* attrib ;

    attrib = AIFF_GetAttribute( ref, AIFF_COPY ) ;

    if( attrib )
    {
    	printf( "Copyright (C) %s\n", attrib ) ;
    	free( attrib ) ;
    }

### Storing attributes

To store an attribute into a writing Audio IFF file, you use:

    int AIFF_SetAttribute(AIFF_Ref w,IFFType typ,char* attribute) ;

`typ` should be a valid identifier, and `attribute` a valid C-string with the content of the attribute.

This function will return 1 on success, < 1 on error.

### Cloning attributes

If you want to edit an existing Audio IFF file, it's often useful to clone all the attributes present on the file to the new edited copy.

You can use the `AIFF_CloneAttributes` function to accomplish this.

    int AIFF_CloneAttributes(AIFF_Ref w, AIFF_Ref r, int cloneMarkers);

The `r` parameter is a reference to an opening-for-reading Audio IFF file from which the attributes will be cloned.

If the `cloneMarkers` parameter is 1, markers (see section 13) will be cloned too (this is not desirable if you have modified the audio content).

This function will return 1 on success, < 1 on error.

## 8. Getting and setting the sound format

    int AIFF_GetAudioFormat(AIFF_Ref r,uint64_t* nSamples,int* channels,double* samplingRate,
    			int* bitsPerSample,int* segmentSize) ;

    int AIFF_SetAudioFormat(AIFF_Ref w,int channels,double samplingRate,
    			int bitsPerSample) ;

You use the `AIFF_GetAudioFormat` function to extract format information about the sound in the Audio IFF file, like number of sample frames, n. of channels, sampling rate, the sample size or the segment size (you have an explanation of these concepts on section 3).

The number of sample frames, `nSamples`, can be used to calculate the length in seconds of the sound:

    uint64_t seconds, nSamples ;
    int channels ;
    double samplingRate ;
    int bitsPerSample ;
    int segmentSize ;

    if( AIFF_GetAudioFormat( ref,&nSamples,&channels,
    			&samplingRate,&bitsPerSample,
    			&segmentSize ) < 1 )
    {
    	puts( "Error" ) ;
    	AIFF_Close( ref ) ;
    }

    seconds = nSamples / samplingRate ;
    /*
     * Print out the seconds in H:MM:SS format
     */
    printf("Length: %lu:%02lu:%02lu \n", (unsigned long) seconds/3600,
    	(unsigned long) (seconds/60)%60, (unsigned long) seconds%60 ) ;

The `AIFF_SetAudioFormat` is used to set the sound format before writing the sound to the Audio IFF file.

You should call this function before calling the sound writing functions (described in the next sections).

Both of these functions will return 1 for success, 0 for errors, -1 for critical errors.

## 9. Reading sound samples: the raw mode

    size_t AIFF_ReadSamples(AIFF_Ref r,void* buffer,size_t len) ;

The above function is used to extract raw sound data from the Audio IFF file. This function is not recommended if you simply want to get the samples or play back the sound, use instead the function described on the next section.

You should pass the reference to the Audio IFF file, a point to a `buffer` which will be filled with sound data, and the `len` in bytes of the buffer which you want filled with sound data.

The function will return the n. of bytes read from the file and stored in buffer, 0 when no more sound is present on the file, and -1 for errors.

The sound data will be presented according to the format provided with the AIFF_GetAudioFormat function, as described on section 3.

Note that LibAiff will do the endian conversion automatically, so the samples will be in native endian form.

Each call of this function will advance the current reading position, so you can extract all of the sound on an Audio IFF file by simply doing repeated calls in a loop.

## 10. Reading sound samples: the normal mode

    int AIFF_ReadSamples32Bit(AIFF_Ref r,int32_t* samples,int nsamples) ;
    int AIFF_ReadSamplesFloat(AIFF_Ref r,float* samples,int nsamples) ;

Use this function to avoid dealing with segments, multiple sample sizes or byte order: it will provide samples into 32-bit (4-byte) signed values or floating-point values (respectively). If the samples are not stored in the requested format in the file, LibAiff will do the necessary conversions.

`nsamples` is the number of sample points you want to read. `samples` is an array of 32-bit signed values or floating-point values (respectively).

The function will return the n. of sample points read from the file. If the returned value is 0, no more samples are present on the file. If it`s -1, an error occurred.

The sampling rate of the samples is provided using the AIFF_GetAudioFormat function.

Each call of this function will advance the current reading position, so you can extract all of the sound on an Audio IFF file by simply doing repeated calls in a loop.

## 11. Seeking

    int AIFF_Seek(AIFF_Ref r,uint64_t sampleFrame) ;

Use this function if you want to seek to a given sample frame into the file.

If you simply want to rewind, pass 0 as `sampleFrame`.

If you want to specify seek positions on seconds, do as in the sample code below:

    uint32_t seconds = 67 ; /* 01:07 */
    uint32_t sampleFrame ;

    sampleFrame = seconds * samplingRate ;
    if( AIFF_Seek( ref,sampleFrame ) < 1 )
    {
    	puts( "Error while seeking!" ) ;
    	AIFF_Close( ref ) ;
    }

Of course calling this function is valid both when using AIFF_ReadSamples and AIFF_ReadSamples32Bit/AIFF_ReadSamplesFloat methods.

This function will return as usual.

## 12. Writing sound data

    int AIFF_StartWritingSamples(AIFF_Ref w) ;

    int AIFF_WriteSamples(AIFF_Ref w,void* buffer,size_t len) ;

    int AIFF_WriteSamples32Bit(AIFF_Ref w,int32_t* samples,int nsamples) ;

    int AIFF_EndWritingSamples(AIFF_Ref w) ;

To start writing sound data, use the `AIFF_StartWritingSamples` function which will return as usual.

### The raw method for writing sound

The `AIFF_WriteSamples` function is not recommended for general sound writing, since it will not do any conversion (except endian-swap) of the sound data (use the normal method instead). Use only this function to do very specific operations.

With this function you should provide a `buffer` filled with `len` bytes of sampled sound data. The sound data should be presented as described in section 3.

Note that you don't have to endian-convert the samples, as LibAiff will do that for you. Your samples will be left untouched; LibAiff will use its internal buffers to do the byte-swapping (if necessary).

It will return as usual.

### The normal method for writing sound

This is the preferred method to write samples to an Audio IFF file. It will convert automatically the samples to the values specified to the AIFF_SetAudioFormat function (which should be called before this one) and will automatically align the samples on segments and deal with the byte-order.

`nsamples` is the number of samples you want to write.

`samples` is an array of `nsamples` signed 32-bit samples.

It will return as usual.

### End writing samples

Simply use the `AIFF_EndWritingSamples` function when you have done delivering the samples. You need to call this function before closing the Audio IFF file or terminating your program.

If this function is not called, the resulting Audio IFF will be incomplete and could not be played back.

This function will return as usual.

## 13. Markers

Audio IFF allows the storage of markers into the file. Markers are references to some position on the sound, including a text describing what`s on that marker (marker name).

In example, you can store a marker to the position 0:28:13 with a text Begin of Part II.

These are the functions used to read & write markers:

    int AIFF_ReadMarker(AIFF_Ref r,int* id,uint32_t* position,char** name) ;

    int AIFF_StartWritingMarkers(AIFF_Ref w) ;

    int AIFF_WriteMarker(AIFF_Ref w,uint32_t position,char* name) ;

    int AIFF_EndWritingMarkers(AIFF_Ref w) ;

### Reading markers

You use the `AIFF_ReadMarker` function to read the markers stored on the file. It will return 1 if a marker is read, 0 when no more markers are stored on file, and -1 on error. This function will automatically advance the reading position, so to read all the markers on a file just call the function repeatedly until it returns 0 (or -1 if an error has occurred).

`name` will point to a valid C-string containing the marker name, or to `NULL` if that marker has not a name. It should be freed when you have done using it.

`position` is the position where the marker points inside the sound, measured on sample frames.

Sample code:

    int id ;
    uint32_t position ;
    uint32_t seconds ;
    char* name ;

    while( 1 )
    {
    	if( AIFF_ReadMarker( ref, &id, &position, &name ) < 1 )
    		break ;

    	seconds = position / samplingRate ;

    	printf("Marker %d --> [%lu:%02lu:%02lu]\n",id,
    		seconds/3600, (seconds/60)%60, seconds%60 ) ;

    	if( name )
    	{
    		printf( "(%s)\n", name ) ;
    		free( name ) ;
    	}
    }

### Writing markers

To start the markers` writing procedure, just call the `AIFF_StartWritingMarkers` (it will return as usual).

Then do one call for each marker to the `AIFF_WriteMarker` function. The `name` argument can be `NULL` if a marker has not a name.

When you have finished writing markers, call the `AIFF_EndWritingMarkers` function. You need to call that function before closing the Audio IFF file or terminating your program, or the resulting Audio IFF file will be damaged and incomplete (LibAiff will complain of that to `stderr`).

## 14. Instrument data

Audio IFF allows the storage of instrument data into the file.

Instrument data is used to store samples in AIFF files and describe them.

LibAiff provides the Instrument data type. The Instrument data type is defined as follows:

    struct s_Loop
    {
    	int16_t playMode ;
    	uint32_t beginLoop ;
    	uint32_t endLoop ;
    } ;

    struct s_Instrument
    {
    	int8_t baseNote ;
    	int8_t detune ;
    	int8_t lowNote ;
    	int8_t highNote ;
    	int8_t lowVelocity ;
    	int8_t highVelocity ;
    	int16_t gain ;
    	struct s_Loop sustainLoop ;
    	struct s_Loop releaseLoop ;
    } ;
    typedef struct s_Instrument Instrument ;

`struct s_Loop` defines the instrument loop points (`sustainLoop` and `releaseLoop`).

The `sustainLoop` is the loop to be played when the instrument sustains a sound. The `releaseLoop` is the loop to be played when the instrument is in the release phase of playing back a sound. The release phase usually occurs after a key on an instrument is released.

The field `playMode` in each loop describes its repetition mode:

    #define kModeNoLooping			0
    #define kModeForwardLooping		1
    #define kModeForwardBackwardLooping	2

Note that if the mode `kModeNoLooping` is used, the remaining fields are to be ignored.

`beginLoop` and `endLoop` reference to positions in the song, measured in sample frames (so they can be used as arguments to the `AIFF_Seek` function).

The remaining fields are used according to the official AIFF specification:

> The detune field determines how much the instrument should alter the pitch of the sound when it is played back. Units are in cents (1/100 of a semitone) and range from -50 to +50. Negative numbers mean that the pitch of the sound should be lowered, while positive numbers mean that it should be raised.

> The lowNote and highNote fields specify the suggested note range on a keyboard for playback of the waveform data. The waveform data should be played if the instrument is requested to play a note between the low and high note numbers, inclusive. The base note does not have to be within this range. Units for lowNote and highNote are MIDI note values.

> The lowVelocity and highVelocity fields specify the suggested range of velocities for playback of the waveform data. The waveform data should be played if the note-on velocity is between low and high velocity, inclusive. Units are MIDI velocity values, 1 (lowest velocity) through 127 (highest velocity).

> The gain is the amount by which to change the gain of the sound when it is played. Units are decibels. For example, 0db means no change, 6db means double the value of each sample point (ie, every additional 6db doubles the gain), while -6db means halve the value of each sample point.

To extract the data from a AIFF file you can use the following function:

    int AIFF_GetInstrumentData(AIFF_Ref r,Instrument* ins) ;

The function returns as usual, and the data will be stored in the structure pointed to by `ins'.

Copyright © 2005, 2006 by Marco Trillo <marcotrillo@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.