libsndfile clib Audio / File I/O

Audio file I/O for PascalAI. Read and write WAV, AIFF, FLAC, OGG, AU, and RAW files with PCM 8/16/24/32-bit, float, and mu-law/a-law sample formats. Supports seeking, metadata tags, format validation, and file-to-file conversion through a single unified API.

ppm install libsndfile

Overview

libsndfile is the standard C library for audio file I/O, maintained by Erik de Castro Lopo. It provides a single, consistent API across dozens of audio file formats without requiring separate codec libraries for each one. The PascalAI binding exposes the full read/write pipeline — open a file, read or write sample frames in your preferred numeric type, seek, read metadata tags, and close.

Sample data is always interleaved: for a stereo file at 44100 Hz, one frame contains two samples (left, right). Reading 1024 frames returns 2048 values. The library handles all endianness and format conversion internally.

CLib package

Requires libsndfile-dev. Ubuntu/Debian: sudo apt install libsndfile-dev

Supported Formats

FormatConstantReadWriteSupported Encodings
WAVsfWAV ($010000)yesyesPCM 8/16/24/32-bit, float, mu-law, a-law
AIFFsfAIFF ($020000)yesyesPCM, float, compressed
FLACsfFLAC ($170000)yesyesLossless compression, PCM 8/16/24-bit
OGGsfOGG ($200000)yesnoVorbis container (read only in libsndfile core)
AUsfAU ($030000)yesyesSun/NeXT audio, PCM, mu-law, a-law, float
RAWsfRAW ($040000)yesyesHeaderless PCM, any rate/depth/channels — must specify format explicitly

Sample Formats

Sub-formatConstantBitsTypical Use
Short / PCM 16ssfPCM_16 ($0002)16CD audio, streaming, most common interchange format
Int / PCM 32ssfPCM_32 ($0004)32Professional DAW sessions, lossless archival
FloatssfFloat ($0006)32Mixing, DSP processing, intermediate computation
DoublessfDouble ($0007)64Scientific audio analysis, highest precision processing
PCM 8ssfPCM_S8 ($0001)8Legacy, telephony, very low-bandwidth storage
PCM 24ssfPCM_24 ($0003)24Studio recording, Blu-ray audio, high-fidelity archival
mu-lawssfULaw ($0010)Telephony (North America/Japan), G.711 compatibility
a-lawssfALaw ($0011)Telephony (Europe), G.711 compatibility

vs. Similar Libraries

LibraryFocusWhen to use libsndfile instead
PortAudioReal-time audio I/O (microphone, speakers)You need to read/write audio files, not stream to/from hardware devices
FFmpegVideo + audio, many lossy codecs (MP3, AAC, H.264)You only need audio files and want a lightweight dependency with no video overhead
SoXCommand-line audio conversion toolYou need a C library with a stable ABI that you can embed directly in your program

Quick Start

Read a WAV file

uses libsndfile;

var sf := OpenRead('recording.wav');
if sf = 0 then
begin
  WriteLn('Failed to open file');
  Exit;
end;

var info := GetInfo(sf);
WriteLn('Sample rate: ' + IntToStr(info.SampleRate));
WriteLn('Channels:    ' + IntToStr(info.Channels));
WriteLn('Frames:      ' + IntToStr(info.Frames));
WriteLn('Duration:    ' + FloatToStr(Duration(sf)) + 's');

{ Read first 1024 frames as 16-bit integers }
var samples := ReadShort(sf, 1024);
WriteLn('Read ' + IntToStr(Length(samples)) + ' samples');

Close(sf);

Write a WAV file (32-bit float)

uses libsndfile;

{ Build a 1-second 440 Hz sine wave at 44100 Hz, mono }
var rate   := 44100;
var frames := rate;
var buf: array of Single;
SetLength(buf, frames);

for var i := 0 to frames - 1 do
  buf[i] := Sin(2.0 * 3.14159265 * 440.0 * i / rate);

{ sfWAV = $010000, ssfFloat = $0006 }
var fmt := $010000 or $0006;
var sf  := OpenWrite('sine440.wav', fmt, rate, 1);
WriteFloat(sf, buf);
Close(sf);

Convert an audio file to a different format

uses libsndfile;

{ Re-encode WAV PCM 16 to FLAC at same sample rate }
{ sfFLAC = $170000, ssfPCM_16 = $0002 }
var dstFmt := $170000 or $0002;
ConvertFile('input.wav', 'output.flac', dstFmt, 44100);
WriteLn('Conversion done');

Types

TSndFile

type
  TSndFile = Integer;  { opaque file handle; 0 = invalid/error }

TSndInfo

type
  TSndInfo = record
    Frames     : Int64;    { total sample frames in file }
    SampleRate : Integer;  { samples per second (e.g. 44100, 48000) }
    Channels   : Integer;  { 1=mono, 2=stereo, 6=5.1 surround, etc. }
    Format     : Integer;  { bitmask: OR of TSndFormat and TSndSubFormat }
    Sections   : Integer;  { number of sections (usually 1) }
    Seekable   : Boolean;  { True if random-access seeking is supported }
  end;

TSndFormat

type
  TSndFormat = (
    sfWAV    = $010000,  { Microsoft WAVE }
    sfAIFF   = $020000,  { Apple AIFF/AIFC }
    sfAU     = $030000,  { Sun/NeXT AU }
    sfFLAC   = $170000,  { FLAC lossless }
    sfOGG    = $200000,  { OGG container (read only) }
    sfRAW    = $040000   { Headerless raw PCM }
  );

TSndSubFormat

type
  TSndSubFormat = (
    ssfPCM_S8  = $0001,  { signed 8-bit PCM }
    ssfPCM_16  = $0002,  { signed 16-bit PCM (CD quality) }
    ssfPCM_24  = $0003,  { signed 24-bit PCM }
    ssfPCM_32  = $0004,  { signed 32-bit PCM }
    ssfFloat   = $0006,  { 32-bit IEEE float }
    ssfDouble  = $0007,  { 64-bit IEEE double }
    ssfULaw    = $0010,  { mu-law (telephony, North America) }
    ssfALaw    = $0011   { a-law (telephony, Europe) }
  );

Open / Close

All I/O operations require an open file handle. OpenRead and OpenWrite cover the common cases; OpenEx is used when you need full control over the format struct, such as for RAW files or format conversion.

FunctionDescription
OpenRead(Path)Open an existing audio file for reading. Returns TSndFile handle, or 0 on error.
OpenWrite(Path, Format, SampleRate, Channels)Create a new audio file for writing. Format is the OR of a TSndFormat and TSndSubFormat constant.
OpenEx(Path, Mode, var Info)Open with a full TSndInfo struct. Mode: 0x10=read, 0x20=write, 0x30=read-write. Required for RAW files.
Close(SF)Flush buffers and close the file handle. Always call this when done.
GetInfo(SF)Return a TSndInfo record describing the open file.

Reading Samples

All read functions take a frame count and return a dynamic array of the corresponding numeric type. Samples are interleaved: for a stereo file, even indices are left-channel and odd indices are right-channel samples.

FunctionReturnsDescription
ReadShort(SF, Count)array of SmallIntRead up to Count frames as 16-bit integers. Most efficient for WAV PCM 16.
ReadInt(SF, Count)array of IntegerRead up to Count frames as 32-bit integers.
ReadFloat(SF, Count)array of SingleRead up to Count frames as 32-bit floats. Values normalized to [-1.0, 1.0].
ReadDouble(SF, Count)array of DoubleRead up to Count frames as 64-bit doubles. Highest precision.
ReadAllFloat(SF)array of SingleRead the entire file in one call as floats. Convenience wrapper — allocates Frames * Channels elements.
Tip — frame count vs. sample count

The array length returned is framesRead * channels, not framesRead. A stereo file yields twice as many array elements as frames requested.

Writing Samples

Write functions accept a dynamic array and return the number of frames actually written. The array length must be a multiple of the channel count.

FunctionReturnsDescription
WriteShort(SF, Data)Int64Write 16-bit integer frames. Data must be interleaved.
WriteInt(SF, Data)Int64Write 32-bit integer frames.
WriteFloat(SF, Data)Int64Write 32-bit float frames. Values should be in [-1.0, 1.0].
WriteDouble(SF, Data)Int64Write 64-bit double frames.

Seeking

Seeking is supported on all formats except raw streams where TSndInfo.Seekable is False. Positions are in frames, not bytes or samples.

FunctionDescription
Seek(SF, Frames, Whence)Move the read/write position. Whence: 0=from start, 1=from current, 2=from end. Returns new frame position.
Tell(SF)Return the current frame position.
uses libsndfile;

var sf   := OpenRead('long.wav');
var info := GetInfo(sf);

{ Jump to the halfway point }
Seek(sf, info.Frames div 2, 0);
WriteLn('Position after seek: ' + IntToStr(Tell(sf)));

var tail := ReadAllFloat(sf);
WriteLn('Samples in second half: ' + IntToStr(Length(tail)));
Close(sf);

Metadata

libsndfile supports string tags embedded in file formats that carry them (WAV INFO chunks, AIFF annotations, FLAC Vorbis comments). Tags are identified by well-known key names.

FunctionDescription
GetString(SF, Key)Read a metadata tag. Returns empty string if the key is absent. Valid keys: 'title', 'artist', 'album', 'comment', 'copyright', 'date'.
SetString(SF, Key, Value)Write a metadata tag. Must be called before writing sample data on new files.
uses libsndfile;

var sfIn  := OpenRead('source.wav');
WriteLn('Title:  ' + GetString(sfIn, 'title'));
WriteLn('Artist: ' + GetString(sfIn, 'artist'));
Close(sfIn);

{ Write tags to a new FLAC file }
var sfOut := OpenWrite('tagged.flac', $170000 or $0002, 44100, 2);
SetString(sfOut, 'title',  'My Track');
SetString(sfOut, 'artist', 'PascalAI Band');
SetString(sfOut, 'date',   '2026');
{ ... write samples ... }
Close(sfOut);

Format Utilities

FunctionDescription
FormatCheck(Format, SampleRate, Channels)Return True if the combination of major format, sub-format, sample rate, and channel count is valid before opening for write.
FormatName(Format)Return a human-readable description of a format integer, e.g. 'WAV (Microsoft)'.
Duration(SF)Return the file duration in seconds as a Double (Frames / SampleRate).

File Conversion

Convert an audio file from any readable format to any writable format in a single call. The library handles resampling if DstRate differs from the source rate.

FunctionDescription
ConvertFile(SrcPath, DstPath, DstFormat, DstRate)Read SrcPath and write DstPath in the specified format and sample rate. DstFormat is the OR of major and sub-format constants.

Info

FunctionDescription
LibSndFileVersionReturn the version string of the underlying libsndfile C library, e.g. 'libsndfile-1.2.2'.

Package Info

Version1.0.0
Typeclib
C Librarylibsndfile-dev
Authorgustavo

System Requirements

libsndfile-dev

Ubuntu/Debian:
sudo apt install libsndfile-dev

Formats Quick-Ref

sfWAV = $010000
sfAIFF = $020000
sfAU = $030000
sfFLAC = $170000
sfOGG = $200000
sfRAW = $040000

ssfPCM_16 = $0002
ssfPCM_32 = $0004
ssfFloat = $0006
ssfDouble = $0007

Combine with OR: e.g.
$010000 or $0002 = WAV PCM16

Functions

  • OpenRead
  • OpenWrite
  • OpenEx
  • Close / GetInfo
  • ReadShort / ReadInt
  • ReadFloat / ReadDouble
  • ReadAllFloat
  • WriteShort / WriteInt
  • WriteFloat / WriteDouble
  • Seek / Tell
  • GetString / SetString
  • FormatCheck / FormatName
  • Duration
  • ConvertFile
  • LibSndFileVersion

See Also