Fast audio resampling library for C and C++.
This library focuses on speed at the expense of audio quality, for scenarios where correct audio processing is not needed. For that it takes many shortcuts to reduce processing and latency.
If you are looking for a high quality resampling library for offline audio processing, or where audio quality is more important than performance, this project is not suited. Look at a resampler like the Opus Silk resampler instead.
C
#include "libfar.h"
// Upsample float stereo audio from 22050 Hz to 44100 Hz.
byte32* upsample(const byte32* buffer, size_t size)
{
const size_t size_out = size * 2;
const size_t aligned_size_out = (size_out + 31) & ~(size_t)31;
char32* buf_out = far_malloc_align32(aligned_size_out);
const int num_channels = 2; // stereo
far_upsample2f32(buffer, size, 22050, num_channels, buf_out, size_out);
return buf_out;
}
C++
#include "libfar.h"
// Convert int16 48kHz audio from mono to stereo.
short512* mono_to_stereo(const short512* buffer, size_t size)
{
const size_t size_out = size * 2;
const size_t aligned_size_out = (size_out + 63) & ~(size_t)63;
short512* buf_out = libfar::malloc_align(aligned_size_out, 64);
libfar::adapt_ch1x2s16(buffer, size, 48000, buf_out, size_out);
return buf_out;
}
Internally functions names are wrapped into the FAR_FN
macro to allow inserting an optional prefix for C usage (defined by FAR_FN_PREFIX
).
C
Functions are prefixed with FAR_FN_PREFIX
, which defaults to far_
but can be redefined by the user:
far_upsample2f32(...);
C++
Functions are enclosed inside the libfar
namespace:
libfar::upsample2f32(...);
The FAR_FN_PREFIX
preprocessor definition is ignored.
libfar
supports 3 different audio sample types:
Sample type | Kind | Size | Range | Description |
---|---|---|---|---|
uint8 |
Integer | 1 byte | [0:255] | Low-resolution 8-bit format, generally only used to achieve retro 8-bit effects. Avoid this format for anything else, as its resolution is too low and produces distorsions. |
int16 |
Integer | 2 bytes | [-32768:32767] | Most common audio sample format for playback and storage. |
float |
Floating-point | 4 bytes | [-1.0:1.0] | Used by some game engines (Unity3D) or as intermediate type for audio pipelines while applying effects to retain a high precision and avoid distorsion. |
C
In C, there is no built-in boolean type. As a fallback, libfar
defines a far_bool
type backed by an int32_t
type and equal to 0
for false
and -1
(bit pattern 0xFFFFFFFF) for true
.
typedef int32_t far_bool;
#define far_true ((far_bool)-1)
#define far_false ((far_bool)0)
C++
In C++ for convenience far_bool
is an alias of the built-in boolean type bool
. Developers are encouraged to use bool
directly.
using far_bool = bool;
constexpr bool far_true = true;
constexpr bool far_false = false;
Buffers are over-aligned compared to standard C/C++ rules to improve performance with SIMD. Special types aliases are defined for those buffers to make the alignment requirement explicit via the type name. There is currently no compile-time check, and it is still possible to pass the wrong type, so developers should be careful.
Sample type | Alignment | Aligned type alias |
---|---|---|
Unspecified* | 4 bytes | byte4 |
Unspecified* | 8 bytes | byte8 |
Unspecified* | 16 bytes | byte16 |
Unspecified* | 32 bytes | byte32 |
int16 |
2 bytes | int16 |
int16 |
16 bytes | short128 |
int16 |
32 bytes | short256 |
int16 |
32 bytes | short512 |
float |
4 bytes | float |
float |
16 bytes | float128 |
float |
32 bytes | float256 |
float |
32 bytes | float512 |
*Unspecified sample types indicate only an alignment, without specifying an actual type. This is useful for functions which can operate on any sample type, but still require an aligned buffer.
Typically the following SIMD implementations requires some specific alignment:
- SSE, SSE2, ..., SSE4.2 : 16 bytes (128 bits)
- AVX, AVX2 : 32 bytes (256 bits)
- AVX512 : 64 bytes (512 bits)
Types of a given alignment can safely be cast to a lower alignment. Therefore most generic dispatching functions take some 64-byte aligned buffers to not lose any generality.
C++
// Generic dispatcher function func1().
byte16* ptr16 = ...
libfar::func1((const byte4*)ptr16, ...); // OK; cast to lower alignment.
// Specific SSE implementation of func1()
byte16* ptr16 = ...
libfar::func1_sse(ptr16, ...); // OK; SSE explicitly requires 16-byte alignment.
Default allocators are based on the standard library's aligned_alloc()
. Custom allocators can be defined by defining the FAR_CUSTOM_ALLOCATORS
preprocessor symbol to avoid defining the built-in allocators, and defining them manually instead.
Note: If defining the allocators generically for both C and C++, remember to use the FAR_FN()
macro. Otherwise you can use directly the prefix (default: far_
) for C or the namespace (libfar
) for C++.
char* FAR_FN(malloc_align)(size_t size, size_t align) {
// ...
}
void FAR_FN(free_align)(void* ptr) {
// ...
}
byte32* FAR_FN(malloc_align32)(size_t size) {
// ...
}
void FAR_FN(free_align32)(byte32* ptr) {
// ...
}
C++
On C++ only, some templated versions are provided for convenience, which deduct the alignment from the sample type alias.
short512* buffer = libfar::malloc_align<short512>(size); // 64-byte aligned
float128* buffer = libfar::malloc_align<float128>(size); // 16-byte aligned
Change the sample rate by an integral factor.
Name | Sample type | Description |
---|---|---|
upsample2f32 |
float |
Upsample 1:2 |
upsample3f32 |
float |
Upsample 1:3 |
downsample2f32 |
float |
Downsample 2:1 |
downsample3f32 |
float |
Downsample 3:1 |
C
size_t size_out = 3 * size_in;
float512* buf_out =(float512*)far_malloc_align64(size_out);
far_upsample3f32(buf_in, size_in, 48000, 2, buf_out, size_out);
C++
size_t size_out = size_in / 2;
float512* buf_out = libfar::malloc_align<float512>(size_out);
libfar::downsample2f32(buf_in, size_in, 44100, 1, buf_out, size_out);
Change the number of audio channels.
Name | Sample type | Input | Output |
---|---|---|---|
adapt_ch1x2s16 |
int16 |
Mono (1) | Stereo (2) |
adapt_ch1x2f32 |
float |
Mono (1) | Stereo (2) |
adapt_ch2x1s16 |
int16 |
Stereo (2) | Mono (1) |
adapt_ch2x1f32 |
float |
Stereo (2) | Mono (1) |
Utilities for allocating and deallocating aligned memory buffers.
Name | Description |
---|---|
malloc_align(size, align) |
Allocate a block of memory with the given size and alignment. |
free_align(ptr) |
Free a block of memory allocated with malloc_align . |
malloc_align16(size) |
Allocate a 16-byte aligned block of memory with the given size. Default implementation is a shorthand for malloc_align(size, 16) . Custom implementations can optimize the allocation based on the compile-time size. |
free_align16(ptr) |
Free a block of memory allocated with malloc_align16 . |
malloc_align32(size) |
Allocate a 32-byte aligned block of memory with the given size. Default implementation is a shorthand for malloc_align(size, 32) . Custom implementations can optimize the allocation based on the compile-time size. |
free_align32(ptr) |
Free a block of memory allocated with malloc_align32 . |
malloc_align64(size) |
Allocate a 64-byte aligned block of memory with the given size. Default implementation is a shorthand for malloc_align(size, 64) . Custom implementations can optimize the allocation based on the compile-time size. |
free_align64(ptr) |
Free a block of memory allocated with malloc_align64 . |
C++
In C++, an extra templated helper is available which deduces the alignment from the type alias, which redirects to the corresponding malloc_alignN()
variant, where N
is the deduced alignment.
template <typename T>
T* malloc_align(size_t size);
The template is only instantiated for the intX
and floatX
type aliases.
Template instantiation | Returned buffer alignment | Implementation |
---|---|---|
malloc_align<float128>(size) |
16 bytes | malloc_align16() |
malloc_align<float256>(size) |
32 bytes | malloc_align32() |
malloc_align<float512>(size) |
64 bytes | malloc_align64() |
malloc_align<short128>(size) |
16 bytes | malloc_align16() |
malloc_align<short256>(size) |
32 bytes | malloc_align32() |
malloc_align<short512>(size) |
64 bytes | malloc_align64() |
Utilities to detect CPU features at runtime and dynamically select the fastest implementation of each library function available on the current host CPU. This is generally used internally only.
Name | Description |
---|---|
void cpuid_init() |
Query and cache the hardware feature support for the host machine. Called once automatically before any of the other functions below; the result is cached after that. |
far_bool has_sse() |
Return far_true if SSE is available on the host machine. |
far_bool has_sse2() |
Return far_true if SSE2 is available on the host machine. |
far_bool has_sse3() |
Return far_true if SSE3 is available on the host machine. |
far_bool has_ssse3() |
Return far_true if SSSE3 is available on the host machine. |
far_bool has_sse41() |
Return far_true if SSE4.1 is available on the host machine. |
far_bool has_sse42() |
Return far_true if SSE4.2 is available on the host machine. |