Skip to content
This repository was archived by the owner on May 27, 2026. It is now read-only.

Latest commit

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

SAF — Simple Audio Format

CI

A minimal, portable, header-only C library for a dead-simple audio format. No magic numbers, no validation overhead, no dependencies. You own the data, you own the responsibility.

Philosophy

Most audio formats carry significant overhead — chunk negotiation, codec detection, metadata sprawl. SAF doesn't. The format assumes the user knows what they're doing. If you give it a file, it trusts you. This makes it fast, simple, and easy to embed anywhere.

Format Specification

OffsetSizeTypeDescription
04uint32Sample rate (little-endian)
41uint8Channel count
51uint8Bit depth
6...rawPCM samples (interleaved)

Total header size: 6 bytes.

Samples are raw interleaved PCM. Stereo audio is stored LRLRLR... No padding, no alignment, no checksums. File length determines data length.

Supported bit depths: 8, 16, 32 (determined by your data — SAF doesn't enforce this).

Usage

SAF is header-only. Copy saf.h into your project.

In exactly one.c file, define SAF_IMPL before including:

#defineSAF_IMPL#include"saf.h"

All other files just include normally:

#include"saf.h"

Writing

SAF_Headerheader= {
.sample_rate=44100,
.channels=1,
.bit_depth=16,
};
int16_t*samples=/* your audio data */;
size_tcount=/* number of samples */;
SAF_RetCoderet=saf_write("audio.saf", header, samples, count);
if (ret!=SAF_OK)
fprintf(stderr, "Error: %s\n", saf_strerror(ret));

Reading

SAF_Headerheader;
void*samples=NULL;
size_tsample_count=0;
SAF_RetCoderet=saf_read("audio.saf", &header, &samples, &sample_count);
if (ret!=SAF_OK)
fprintf(stderr, "Error: %s\n", saf_strerror(ret));
int16_t*pcm= (int16_t*)samples;
/* use pcm... */saf_free(&samples);

The library allocates the sample buffer. Always free with saf_free — never free() directly, in case the implementation changes.

API

// Write audio data to a .saf fileSAF_RetCodesaf_write(constchar*filename, SAF_Headerheader, constvoid*samples, size_tsample_count);
// Read a .saf file — allocates sample buffer, caller must saf_free()SAF_RetCodesaf_read(constchar*filename, SAF_Header*header, void**samples, size_t*sample_count);
// Free a buffer allocated by saf_read — nulls the pointervoidsaf_free(void**samples);
// Return human-readable string for a return codeconstchar*saf_strerror(SAF_RetCodecode);

Return Codes

CodeMeaning
SAF_OKSuccess
SAF_ERR_OPENFailed to open file
SAF_ERR_WRITEFailed to write file
SAF_ERR_READFailed to read file
SAF_ERR_MEMMemory allocation failed

Building the Test

make # build and run test
make clean # clean artifacts

Requires GCC and libm.

Portability

SAF manually serializes header fields byte-by-byte, so it is endian-safe and makes no assumptions about struct layout or compiler padding. Tested on Linux (GCC, Clang). Should work on any C99-compliant compiler.

License

MIT — see LICENSE.

About

Simple Audio Format — minimal header-only C library

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages