summaryrefslogtreecommitdiff
path: root/Source/3rdParty/Wuff
diff options
context:
space:
mode:
Diffstat (limited to 'Source/3rdParty/Wuff')
-rw-r--r--Source/3rdParty/Wuff/wuff.c203
-rw-r--r--Source/3rdParty/Wuff/wuff.h274
-rw-r--r--Source/3rdParty/Wuff/wuff_config.h50
-rw-r--r--Source/3rdParty/Wuff/wuff_convert.c827
-rw-r--r--Source/3rdParty/Wuff/wuff_convert.h48
-rw-r--r--Source/3rdParty/Wuff/wuff_internal.c540
-rw-r--r--Source/3rdParty/Wuff/wuff_internal.h171
-rw-r--r--Source/3rdParty/Wuff/wuff_memory.c17
8 files changed, 2130 insertions, 0 deletions
diff --git a/Source/3rdParty/Wuff/wuff.c b/Source/3rdParty/Wuff/wuff.c
new file mode 100644
index 0000000..f359733
--- /dev/null
+++ b/Source/3rdParty/Wuff/wuff.c
@@ -0,0 +1,203 @@
+#include <string.h>
+
+#include "wuff_config.h"
+#include "wuff.h"
+#include "wuff_internal.h"
+
+
+wuff_sint32 wuff_open(struct wuff_handle ** handle_pointer, struct wuff_callback * callback, void * userdata)
+{
+ struct wuff_handle * handle;
+ wuff_sint32 wuff_status;
+
+ if (handle_pointer == NULL || callback == NULL)
+ return WUFF_INVALID_PARAM;
+
+ handle = wuff_alloc(sizeof(struct wuff_handle));
+ if (handle == NULL)
+ return WUFF_MEMALLOC_ERROR;
+
+ memset(handle, 0, sizeof(struct wuff_handle));
+ handle->buffer.data = NULL;
+ handle->callback = callback;
+ handle->userdata = userdata;
+
+ wuff_status = wuff_setup(handle);
+ if (wuff_status < 0)
+ {
+ wuff_cleanup(handle);
+ return wuff_status;
+ }
+
+ *handle_pointer = handle;
+
+ return WUFF_SUCCESS;
+}
+
+wuff_sint32 wuff_close(struct wuff_handle * handle)
+{
+ wuff_sint32 wuff_status;
+
+ if (handle == NULL)
+ return WUFF_INVALID_PARAM;
+
+ wuff_status = wuff_cleanup(handle);
+ WUFF_STATUS_BAIL()
+
+ return WUFF_SUCCESS;
+}
+
+wuff_sint32 wuff_seek(struct wuff_handle * handle, wuff_uint64 offset)
+{
+ wuff_sint32 wuff_status;
+ wuff_uint64 seek_offset;
+
+ if (handle == NULL)
+ return WUFF_INVALID_PARAM;
+
+ /* Clamp offset to stream length. */
+ offset = offset <= handle->stream.length ? offset : handle->stream.length;
+ seek_offset = offset * handle->stream.header.block_size;
+ wuff_status = handle->callback->seek(handle->userdata, handle->stream.data.offset + seek_offset);
+ WUFF_STATUS_BAIL()
+
+ handle->stream.position = offset;
+ handle->output.block_offset = 0;
+
+ /* A new position requires an empty buffer. */
+ wuff_status = wuff_buffer_clear(handle);
+ WUFF_STATUS_BAIL()
+
+ return WUFF_SUCCESS;
+}
+
+wuff_sint32 wuff_tell(struct wuff_handle * handle, wuff_uint64 * offset)
+{
+ if (handle == NULL)
+ return WUFF_INVALID_PARAM;
+
+ *offset = handle->stream.position;
+
+ return WUFF_SUCCESS;
+}
+
+wuff_sint32 wuff_stream_info(struct wuff_handle * handle, struct wuff_info * info)
+{
+ if (handle == NULL || info == NULL)
+ return WUFF_INVALID_PARAM;
+
+ info->format = handle->stream.format;
+ info->channels = handle->stream.header.channels;
+ info->sample_rate = handle->stream.header.sample_rate;
+ info->bits_per_sample = handle->stream.header.bits_per_sample;
+ info->length = handle->stream.length;
+ /* Think about adding channel mapping and perhaps other things. */
+
+ return WUFF_SUCCESS;
+}
+
+wuff_sint32 wuff_format(struct wuff_handle * handle, wuff_uint16 format)
+{
+ wuff_sint32 wuff_status;
+
+ if (handle == NULL)
+ return WUFF_INVALID_PARAM;
+ else if (format >= WUFF_FORMAT_MAX)
+ return WUFF_FORMAT_UNSUPPORTED;
+
+ /* A format change resets the position to the start of the block. */
+ wuff_status = wuff_seek(handle, handle->stream.position);
+ WUFF_STATUS_BAIL()
+
+ wuff_status = wuff_set_output_format(handle, format);
+ WUFF_STATUS_BAIL()
+
+ return WUFF_SUCCESS;
+}
+
+wuff_sint32 wuff_read(struct wuff_handle * handle, wuff_uint8 * out_buffer, size_t * out_size)
+{
+ size_t current_offset;
+ size_t r_samples, num_samples;
+ wuff_uint8 head_offset, head, tail, sample_size;
+ wuff_uint8 * in_buffer;
+ wuff_sint32 wuff_status;
+
+ if (handle == NULL || out_buffer == NULL || out_size == NULL)
+ return WUFF_INVALID_PARAM;
+
+ if (*out_size == 0)
+ return WUFF_SUCCESS;
+
+ sample_size = (wuff_uint8)handle->output.bytes_per_sample;
+
+ /* Calculating the number of samples that fit into the application buffer. */
+ /* The first and last sample may be truncated. */
+ current_offset = handle->output.block_offset;
+ head_offset = current_offset % sample_size;
+ head = head_offset == 0 ? 0 : sample_size - head_offset;
+ num_samples = wuff_calculate_samples(*out_size, sample_size, &head, &tail);
+
+ /* Requesting the number of samples from the buffer. */
+ /* Calculate the new sample count if necessary and write the output. */
+ r_samples = num_samples;
+ wuff_status = wuff_buffer_request(handle, &in_buffer, &r_samples);
+ WUFF_STATUS_BAIL()
+ else if (r_samples == 0)
+ {
+ /* Possible EOF. */
+ *out_size = 0;
+ }
+ else
+ {
+ if (r_samples == 1 && head != 0)
+ {
+ /* Only the first truncated sample fits. */
+ /* I really hope nobody will use small buffers like this. */
+ num_samples = 0;
+ tail = 0;
+ }
+ else
+ {
+ /* At this point the first (possibly truncated) sample will be fully written. */
+ /* Subtract the first and last sample from the count if they're truncated. */
+ if (r_samples < num_samples)
+ tail = 0;
+ num_samples = r_samples - !!head - !!tail;
+ }
+
+ handle->output.function(out_buffer, in_buffer, num_samples, head_offset, head, tail);
+
+ /* Report the number of bytes written. */
+ *out_size = num_samples * sample_size + head + tail;
+
+ /* Adjust the block offset and sample position. */
+ current_offset += *out_size;
+ if (current_offset >= handle->output.block_size)
+ {
+ handle->stream.position += current_offset / handle->output.block_size;
+ handle->output.block_offset = current_offset % handle->output.block_size;
+ }
+ else
+ {
+ handle->output.block_offset = current_offset;
+ }
+
+ /* Release the fully processed samples from the buffer. */
+ wuff_status = wuff_buffer_release(handle, head_offset + head == sample_size ? num_samples + 1 : num_samples);
+ WUFF_STATUS_BAIL()
+ }
+
+ return WUFF_SUCCESS;
+}
+
+void wuff_version(struct wuff_version * version)
+{
+ if (version == NULL)
+ return;
+
+ version->major = WUFF_VERSION_MAJOR;
+ version->minor = WUFF_VERSION_MINOR;
+ version->build = WUFF_VERSION_BUILD;
+ version->revision = WUFF_VERSION_REVISION;
+}
diff --git a/Source/3rdParty/Wuff/wuff.h b/Source/3rdParty/Wuff/wuff.h
new file mode 100644
index 0000000..c7cc109
--- /dev/null
+++ b/Source/3rdParty/Wuff/wuff.h
@@ -0,0 +1,274 @@
+/*
+ * Wuff - A very basic WAVE reader
+ */
+
+#ifndef WUFF_H
+#define WUFF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define WUFF_VERSION_MAJOR 0
+#define WUFF_VERSION_MINOR 0
+#define WUFF_VERSION_BUILD 0
+#define WUFF_VERSION_REVISION 2
+
+
+#ifndef WUFF_API_OVERRIDE
+ #if defined(_WIN32) && defined(WUFF_DYNAMIC_LIB)
+ #define WUFF_EXPORT __declspec(dllexport)
+ #define WUFF_IMPORT __declspec(dllimport)
+ #else
+ #define WUFF_EXPORT
+ #define WUFF_IMPORT
+ #endif
+#endif
+
+#ifdef WUFF_BUILDING_CORE
+ #define WUFF_API WUFF_EXPORT
+#else
+ #define WUFF_API WUFF_IMPORT
+#endif
+
+
+#ifdef WUFF_FORCE_STDINT_H
+ #include <stdint.h>
+typedef uint8_t wuff_uint8;
+typedef int8_t wuff_sint8;
+typedef uint16_t wuff_uint16;
+typedef int16_t wuff_sint16;
+typedef uint32_t wuff_uint32;
+typedef int32_t wuff_sint32;
+ #ifdef WUFF_NO_64BIT_TYPE
+typedef uint32_t wuff_uint64;
+typedef int32_t wuff_sint64;
+ #else
+typedef uint64_t wuff_uint64;
+typedef int64_t wuff_sint64;
+ #endif
+#elif _MSC_VER
+typedef unsigned __int8 wuff_uint8;
+typedef signed __int8 wuff_sint8;
+typedef unsigned __int16 wuff_uint16;
+typedef signed __int16 wuff_sint16;
+typedef unsigned __int32 wuff_uint32;
+typedef signed __int32 wuff_sint32;
+typedef unsigned __int64 wuff_uint64;
+typedef signed __int64 wuff_sint64;
+#else
+typedef unsigned char wuff_uint8;
+typedef signed char wuff_sint8;
+typedef unsigned short wuff_uint16;
+typedef signed short wuff_sint16;
+typedef unsigned int wuff_uint32;
+typedef signed int wuff_sint32;
+ #ifdef WUFF_NO_64BIT_TYPE
+typedef unsigned long wuff_uint64;
+typedef signed long wuff_sint64;
+ #else
+typedef unsigned long long wuff_uint64;
+typedef signed long long wuff_sint64;
+ #endif
+#endif
+
+/** @file */
+/**
+ * Opaque structure used to identify the open Wuff streams.
+ */
+struct wuff_handle;
+
+/**
+ * Callbacks that control the delivery of the data of the WAVE file.
+ *
+ * The return values of the functions indicate their status. A zero or positive
+ * value means success and a negative value failure. The macros WUFF_SUCCESS and
+ * WUFF_ERROR, or a value equal or below WUFF_USER_ERROR can be used. The error
+ * value will be returned by the function called by the application.
+ */
+struct wuff_callback
+{
+ /**
+ * The read callback requests the linking application to write at least
+ * 'size' bytes into the memory where 'buffer' is pointing to. The value
+ * pointed to by 'size' must be update to the actual number of bytes
+ * written. Zero will be interepreted as the end-of-file.
+ *
+ * @param userdata The userdata set with wuff_open.
+ * @param buffer A pointer to the memory where the data can be written to.
+ * @param size A pointer to the size of the buffer and the bytes written.
+ */
+ wuff_sint32 (* read)(void * userdata, wuff_uint8 * buffer, size_t * size);
+
+ /**
+ * The seek callback requests the linking application to seek to a new byte
+ * offset in the WAVE data. The next call to the read callback must then
+ * write data starting from this position. The offset is always relative
+ * to the beginning of the WAVE data.
+ *
+ * @param userdata The userdata set with wuff_open.
+ * @param offset The new offset.
+ */
+ wuff_sint32 (* seek)(void * userdata, wuff_uint64 offset);
+
+ /**
+ * The tell callback requests the linking application to write the current
+ * byte position to the integer pointed to by 'offset'.
+ *
+ * @param userdata The userdata set with wuff_open.
+ * @param offset A pointer to an integer where the current position can be written to.
+ */
+ wuff_sint32 (* tell)(void * userdata, wuff_uint64 * offset);
+};
+
+
+/**
+ * Stream information structure.
+ */
+struct wuff_info
+{
+ wuff_uint16 format; /**< The format of the stream.
+ * See "Wuff raw sample formats" below. */
+ wuff_uint16 channels; /**< The number of channels in the stream. */
+ wuff_uint32 sample_rate; /**< The sample rate in hertz. */
+ wuff_uint16 bits_per_sample; /**< The number of bits per sample. */
+ wuff_uint64 length; /**< The length of the stream in samples. */
+};
+
+
+/**
+ * Version information structure.
+ */
+struct wuff_version
+{
+ wuff_uint16 major;
+ wuff_uint16 minor;
+ wuff_uint16 build;
+ wuff_uint16 revision;
+};
+
+
+/**
+ * Opens a new Wuff stream. This will read from the callbacks immediately, make
+ * sure they're ready. It will check if the WAVE file is supported.
+ *
+ * @param handle A pointer to pointer of a wuff_handle that will be
+ * initialized if the function succeeds.
+ * @param callback The callbacks for the data of the WAVE file.
+ * @param userdata A void pointer that will be passed to the callbacks.
+ * @return Returns a negative value if an error occured.
+ */
+WUFF_API wuff_sint32 wuff_open(struct wuff_handle ** handle, struct wuff_callback * callback, void * userdata);
+
+/**
+ * Closes a Wuff stream.
+ *
+ * @param handle The Wuff stream handle.
+ * @return Returns a negative value if an error occured.
+ */
+WUFF_API wuff_sint32 wuff_close(struct wuff_handle * handle);
+
+/**
+ * Fills the wuff_info struct with information about the stream.
+ *
+ * @param handle The Wuff stream handle.
+ * @param info A pointer to a wuff_info struct.
+ * @return Returns a negative value if an error occured.
+ */
+WUFF_API wuff_sint32 wuff_stream_info(struct wuff_handle * handle, struct wuff_info * info);
+
+/**
+ * Sets the output format of the decoder. A new format resets the decoder output
+ * to the beginning of the current block (the sample of the first channel).
+ *
+ * @param handle The Wuff stream handle.
+ * @param format The new output format.
+ * @return Returns a negative value if an error occured.
+ */
+WUFF_API wuff_sint32 wuff_format(struct wuff_handle * handle, wuff_uint16 format);
+
+/**
+ * Decodes samples to the passed memory location. The size_t pointer points to
+ * the maximum number of bytes that can be written to the buffer. This count
+ * will be adjusted to the number of bytes written to the buffer.
+ *
+ * @param handle The Wuff stream handle.
+ * @param buffer The buffer to write to.
+ * @param size The maximum number of bytes to write to the buffer.
+ * @return Returns a negative value if an error occured.
+ */
+WUFF_API wuff_sint32 wuff_read(struct wuff_handle * handle, wuff_uint8 * buffer, size_t * size);
+
+/**
+ * Seeks to a sample location.
+ * The next call to wuff_read will return samples starting from this position.
+ *
+ * @param handle The Wuff stream handle.
+ * @param offset The sample offset to seek to.
+ * @return Returns a negative value if an error occured.
+ */
+WUFF_API wuff_sint32 wuff_seek(struct wuff_handle * handle, wuff_uint64 offset);
+
+/**
+ * Sets the current position.
+ *
+ * @param handle The Wuff stream handle.
+ * @param offset A pointer to a integer that will receive the sample offset.
+ * @return Returns a negative value if an error occured.
+ */
+WUFF_API wuff_sint32 wuff_tell(struct wuff_handle * handle, wuff_uint64 * offset);
+
+/**
+ * Copies the Wuff version of the binary into the struct.
+ * For compile-time version information use the WUFF_VERSION_MAJOR,
+ * WUFF_VERSION_MINOR, WUFF_VERSION_BUILD, and WUFF_VERSION_REVISION macros.
+ *
+ * @param version A pointer to a wuff_version struct that will receive the
+ * version information.
+ */
+WUFF_API void wuff_version(struct wuff_version * version);
+
+
+/* Wuff raw sample formats. */
+#define WUFF_FORMAT_PCM_U8 0
+#define WUFF_FORMAT_PCM_S16 1
+#define WUFF_FORMAT_PCM_S24 2
+#define WUFF_FORMAT_PCM_S32 3
+#define WUFF_FORMAT_IEEE_FLOAT_32 4
+#define WUFF_FORMAT_IEEE_FLOAT_64 5
+#define WUFF_FORMAT_MAX 6
+
+
+/* Success and error return values for all functions. */
+#define WUFF_STREAM_EOF 100
+
+#define WUFF_SUCCESS 0
+
+#define WUFF_ERROR -1
+#define WUFF_INVALID_PARAM -2
+#define WUFF_MEMALLOC_ERROR -3
+
+#define WUFF_STREAM_NOT_RIFF -100
+#define WUFF_STREAM_NOT_WAVE -101
+#define WUFF_STREAM_INVALID -102
+#define WUFF_STREAM_ZERO_CHANNELS -103
+#define WUFF_STREAM_ZERO_SAMPLE_RATE -104
+#define WUFF_STREAM_ZERO_BITS_PER_SAMPLE -105
+#define WUFF_STREAM_FORMAT_CHUNK_MISSING -106
+#define WUFF_STREAM_DATA_CHUNK_MISSING -107
+#define WUFF_STREAM_CHUNK_NOT_FOUND -108
+
+#define WUFF_FORMAT_UNSUPPORTED -200
+
+#define WUFF_BUFFER_INVALID_SIZE -300
+#define WUFF_BUFFER_INVALID_STREAM_POSITION -301
+
+#define WUFF_USER_ERROR -10000
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WUFF_H */
diff --git a/Source/3rdParty/Wuff/wuff_config.h b/Source/3rdParty/Wuff/wuff_config.h
new file mode 100644
index 0000000..ed17005
--- /dev/null
+++ b/Source/3rdParty/Wuff/wuff_config.h
@@ -0,0 +1,50 @@
+#ifndef WUFF_CONFIG_H
+#define WUFF_CONFIG_H
+
+/* Defines that the internal code is being built. */
+/* The wuff.h header uses this to change export and import macros. */
+#define WUFF_BUILDING_CORE
+
+#ifndef WUFF_INLINE_OVERRIDE
+ #ifdef __cplusplus
+ #define WUFF_INLINE inline
+ #else
+ #ifdef _MSC_VER
+ #define WUFF_INLINE __inline
+ #elif __GNUC__
+ #define WUFF_INLINE __inline__
+ #else
+ #define WUFF_INLINE
+ #endif
+ #endif
+#endif
+
+
+#ifndef WUFF_GCC_VISIBILITY_OVERRIDE
+ #if __GNUC__ >= 4
+ #define WUFF_INTERN_API __attribute__((visibility("hidden")))
+ #else
+ #define WUFF_INTERN_API
+ #endif
+#endif
+
+
+#ifdef WUFF_MEMALLOC_OVERRIDE
+ #ifdef __cplusplus
+extern "C" {
+ #endif
+
+ /* Define your own memory allocator. */
+ void * wuff_alloc(size_t size);
+ void wuff_free(void * mem);
+
+ #ifdef __cplusplus
+}
+ #endif
+#else
+WUFF_INTERN_API void * wuff_alloc(size_t size);
+WUFF_INTERN_API void wuff_free(void * mem);
+#endif
+
+
+#endif /* WUFF_CONFIG_H */
diff --git a/Source/3rdParty/Wuff/wuff_convert.c b/Source/3rdParty/Wuff/wuff_convert.c
new file mode 100644
index 0000000..9e60ff5
--- /dev/null
+++ b/Source/3rdParty/Wuff/wuff_convert.c
@@ -0,0 +1,827 @@
+#include <string.h>
+
+#include "wuff_config.h"
+#include "wuff.h"
+#include "wuff_convert.h"
+
+/*
+ * int8 functions.
+ */
+
+WUFF_CONV_FUNC(wuff_int8_to_int8)
+{
+ (void)offset;
+ memcpy(dst, src, samples + head + tail);
+}
+
+WUFF_CONV_FUNC(wuff_int8_to_int16)
+{
+ wuff_sint16 i16;
+ size_t i;
+
+ if (head != 0)
+ {
+ i16 = (src[0] - 128) << 8;
+ memcpy(dst, (wuff_uint8 *)&i16 + offset, head);
+ src += 1;
+ dst += head;
+ }
+
+ for (i = 0; i < samples; i++)
+ {
+ i16 = (src[i] - 128) << 8;
+ memcpy(dst + i * 2, &i16, 2);
+ }
+
+ if (tail != 0)
+ {
+ i16 = (src[samples] - 128) << 8;
+ memcpy(dst + samples * 2, &i16, tail);
+ }
+}
+
+WUFF_CONV_FUNC(wuff_int8_to_int24)
+{
+ wuff_sint32 i24;
+ size_t i;
+
+ if (head != 0)
+ {
+ i24 = (src[0] - 128) << 24;
+ memcpy(dst, (wuff_uint8 *)&i24 + 1 + offset, head);
+ src += 1;
+ dst += head;
+ }
+
+ for (i = 0; i < samples; i++)
+ {
+ i24 = (src[i] - 128) << 24;
+ memcpy(dst + i * 3, (wuff_uint8 *)&i24 + 1, 3);
+ }
+
+ if (tail != 0)
+ {
+ i24 = (src[samples] - 128) << 24;
+ memcpy(dst + samples * 3, (wuff_uint8 *)&i24 + 1, tail);
+ }
+}
+
+WUFF_CONV_FUNC(wuff_int8_to_int32)
+{
+ wuff_sint32 i32;
+ size_t i;
+
+ if (head != 0)
+ {
+ i32 = (src[0] - 128) << 24;
+ memcpy(dst, (wuff_uint8 *)&i32 + offset, head);
+ src += 1;
+ dst += head;
+ }
+
+ for (i = 0; i < samples; i++)
+ {
+ i32 = (src[i] - 128) << 24;
+ memcpy(dst + i * 4, &i32, 4);
+ }
+
+ if (tail != 0)
+ {
+ i32 = (src[samples] - 128) << 24;
+ memcpy(dst + samples * 4, &i32, tail);
+ }
+}
+
+WUFF_CONV_FUNC(wuff_int8_to_float32)
+{
+ float f32;
+ size_t i;
+
+ if (head != 0)
+ {
+ f32 = (float)(src[0] - 128) / 128.0f;
+ memcpy(dst, (wuff_uint8 *)&f32 + offset, head);
+ src += 1;
+ dst += head;
+ }
+
+ for (i = 0; i < samples; i++)
+ {
+ f32 = (float)(src[i] - 128) / 128.0f;
+ memcpy(dst + i * 4, &f32, 4);
+ }
+
+ if (tail != 0)
+ {
+ f32 = (float)(src[samples] - 128) / 128.0f;
+ memcpy(dst + samples * 4, &f32, tail);
+ }
+}
+
+WUFF_CONV_FUNC(wuff_int8_to_float64)
+{
+ double f64;
+ size_t i;
+
+ if (head != 0)
+ {
+ f64 = (double)(src[0] - 128) / 128.0;
+ memcpy(dst, (wuff_uint8 *)&f64 + offset, head);
+ src += 1;
+ dst += head;
+ }
+
+ for (i = 0; i < samples; i++)
+ {
+ f64 = (double)(src[i] - 128) / 128.0;
+ memcpy(dst + i * 8, &f64, 8);
+ }
+
+ if (tail != 0)
+ {
+ f64 = (double)(src[samples] - 128) / 128.0;
+ memcpy(dst + samples * 8, &f64, tail);
+ }
+}
+
+/*
+ * int16 functions.
+ */
+
+WUFF_CONV_FUNC(wuff_int16_to_int8)
+{
+ wuff_sint16 i16;
+ size_t i;
+ (void)offset; (void)head; (void)tail;
+
+ for (i = 0; i < samples; i++)
+ {
+ memcpy(&i16, src + i * 2, 2);
+ dst[i] = (i16 >> 8) + 128;
+ }
+}
+
+WUFF_CONV_FUNC(wuff_int16_to_int16)
+{
+ memcpy(dst, src + offset, samples * 2 + head + tail);
+}
+
+WUFF_CONV_FUNC(wuff_int16_to_int24)
+{
+ wuff_sint16 i16;
+ wuff_sint32 i24;
+ size_t i;
+
+ if (head != 0)
+ {
+ memcpy(&i16, src, 2);
+ i24 = i16 << 16;
+ memcpy(dst, (wuff_uint8 *)&i24 + 1 + offset, head);
+ src += 2;
+ dst += head;
+ }
+
+ for (i = 0; i < samples; i++)
+ {
+ memcpy(&i16, src + i * 2, 2);
+ i24 = i16 << 16;
+ memcpy(dst + i * 3, (wuff_uint8 *)&i24 + 1, 3);
+ }
+
+ if (tail != 0)
+ {
+ memcpy(&i16, src + samples * 2, 2);
+ i24 = i16 << 16;
+ memcpy(dst + samples * 3, (wuff_uint8 *)&i24 + 1, tail);
+ }
+}
+
+WUFF_CONV_FUNC(wuff_int16_to_int32)
+{
+ wuff_sint16 i16;
+ wuff_sint32 i32;
+ size_t i;
+
+ if (head != 0)
+ {
+ memcpy(&i16, src, 2);
+ i32 = i16 << 16;
+ memcpy(dst, (wuff_uint8 *)&i32 + offset, head);
+ src += 2;
+ dst += head;
+ }
+
+ for (i = 0; i < samples; i++)
+ {
+ memcpy(&i16, src + i * 2, 2);
+ i32 = i16 << 16;
+ memcpy(dst + i * 4, &i32, 4);
+ }
+
+ if (tail != 0)
+ {
+ memcpy(&i16, src + samples * 2, 2);
+ i32 = i16 << 16;
+ memcpy(dst + samples * 4, &i32, tail);
+ }
+}
+
+WUFF_CONV_FUNC(wuff_int16_to_float32)
+{
+ wuff_sint16 i16;
+ float f32;
+ size_t i;
+
+ if (head != 0)
+ {
+ memcpy(&i16, src, 2);
+ f32 = (float)i16 / 32768.0f;
+ memcpy(dst, (wuff_uint8 *)&f32 + offset, head);
+ src += 2;
+ dst += head;
+ }
+
+ for (i = 0; i < samples; i++)
+ {
+ memcpy(&i16, src + i * 2, 2);
+ f32 = (float)i16 / 32768.0f;
+ memcpy(dst + i * 4, &f32, 4);
+ }
+
+ if (tail != 0)
+ {
+ memcpy(&i16, src + samples * 2, 2);
+ f32 = (float)i16 / 32768.0f;
+ memcpy(dst + samples * 4, &f32, tail);
+ }
+}
+
+WUFF_CONV_FUNC(wuff_int16_to_float64)
+{
+ wuff_sint16 i16;
+ double f64;
+ size_t i;
+
+ if (head != 0)
+ {
+ memcpy(&i16, src, 2);
+ f64 = (double)i16 / 32768.0;
+ memcpy(dst, (wuff_uint8 *)&f64 + offset, head);
+ src += 2;
+ dst += head;
+ }
+
+ for (i = 0; i < samples; i++)
+ {
+ memcpy(&i16, src + i * 2, 2);
+ f64 = (double)i16 / 32768.0;
+ memcpy(dst + i * 8, &f64, 8);
+ }
+
+ if (tail != 0)
+ {
+ memcpy(&i16, src + samples * 2, 2);
+ f64 = (double)i16 / 32768.0;
+ memcpy(dst + samples * 8, &f64, tail);
+ }
+}
+
+/*
+ * int24 functions.
+ */
+
+WUFF_CONV_FUNC(wuff_int24_to_int8)
+{
+ wuff_sint32 i24 = 0;
+ size_t i;
+ (void)offset; (void)head; (void)tail;
+
+ for (i = 0; i < samples; i++)
+ {
+ memcpy((wuff_uint8 *)&i24 + 1, src + i * 3, 3);
+ dst[i] = (wuff_uint8)((i24 >> 16) + 128);
+ }
+}
+
+WUFF_CONV_FUNC(wuff_int24_to_int16)
+{
+ size_t i;
+
+ if (head != 0)
+ {
+ memcpy(dst, src + 1 + offset, head);
+ src += 3;
+ dst += head;
+ }
+
+ for (i = 0; i < samples; i++)
+ {
+ memcpy(dst + i * 2, src + 1 + i * 3, 2);
+ }
+
+ if (tail != 0)
+ {
+ memcpy(dst + samples * 2, src + 1 + samples * 3, tail);
+ }
+}
+
+WUFF_CONV_FUNC(wuff_int24_to_int24)
+{
+ memcpy(dst, src + offset, samples * 3 + head + tail);
+}
+
+WUFF_CONV_FUNC(wuff_int24_to_int32)
+{
+ wuff_sint32 i32 = 0;
+ size_t i;
+
+ if (head != 0)
+ {
+ memcpy((wuff_uint8 *)&i32 + 1, src, 3);
+ memcpy(dst, (wuff_uint8 *)&i32 + offset, head);
+ src += 3;
+ dst += head;
+ }
+
+ for (i = 0; i < samples; i++)
+ {
+ memcpy((wuff_uint8 *)&i32 + 1, src + i * 3, 3);
+ memcpy(dst + i * 4, &i32, 4);
+ }
+
+ if (tail != 0)
+ {
+ memcpy((wuff_uint8 *)&i32 + 1, src + samples * 3, 3);
+ memcpy(dst + samples * 4, &i32, tail);
+ }
+}
+
+WUFF_CONV_FUNC(wuff_int24_to_float32)
+{
+ wuff_sint32 i24 = 0;
+ float f32;
+ size_t i;
+
+ if (head != 0)
+ {
+ memcpy((wuff_uint8 *)&i24 + 1, src, 3);
+ f32 = (float)((double)i24 / 2147483648.0);
+ memcpy(dst, (wuff_uint8 *)&f32 + offset, head);
+ src += 3;
+ dst += head;
+ }
+
+ for (i = 0; i < samples; i++)
+ {
+ memcpy((wuff_uint8 *)&i24 + 1, src + i * 3, 3);
+ f32 = (float)((double)i24 / 2147483648.0);
+ memcpy(dst + i * 4, &f32, 4);
+ }
+
+ if (tail != 0)
+ {
+ memcpy((wuff_uint8 *)&i24 + 1, src + samples * 3, 3);
+ f32 = (float)((double)i24 / 2147483648.0);
+ memcpy(dst + samples * 4, &f32, tail);
+ }
+}
+
+WUFF_CONV_FUNC(wuff_int24_to_float64)
+{
+ wuff_sint32 i24 = 0;
+ double f64;
+ size_t i;
+
+ if (head != 0)
+ {
+ memcpy((wuff_uint8 *)&i24 + 1, src, 3);
+ f64 = (double)i24 / 2147483648.0;
+ memcpy(dst, (wuff_uint8 *)&f64 + offset, head);
+ src += 3;
+ dst += head;
+ }
+
+ for (i = 0; i < samples; i++)
+ {
+ memcpy((wuff_uint8 *)&i24 + 1, src + i * 3, 3);
+ f64 = (double)i24 / 2147483648.0;
+ memcpy(dst + i * 8, &f64, 8);
+ }
+
+ if (tail != 0)
+ {
+ memcpy((wuff_uint8 *)&i24 + 1, src + samples * 3, 3);
+ f64 = (double)i24 / 2147483648.0;
+ memcpy(dst + samples * 8, &f64, tail);
+ }
+}
+
+/*
+ * int32 functions.
+ */
+
+WUFF_CONV_FUNC(wuff_int32_to_int8)
+{
+ wuff_sint32 i32 = 0;
+ size_t i;
+ (void)offset; (void)head; (void)tail;
+
+ for (i = 0; i < samples; i++)
+ {
+ memcpy(&i32, src + i * 4, 4);
+ dst[i] = (i32 >> 24) + 128;
+ }
+}
+
+WUFF_CONV_FUNC(wuff_int32_to_int16)
+{
+ size_t i;
+
+ if (head != 0)
+ {
+ memcpy(dst, src + 2 + offset, head);
+ src += 4;
+ dst += head;
+ }
+
+ for (i = 0; i < samples; i++)
+ {
+ memcpy(dst + i * 2, src + 2 + i * 4, 2);
+ }
+
+ if (tail != 0)
+ {
+ memcpy(dst + samples * 2, src + 2 + samples * 4, tail);
+ }
+}
+
+WUFF_CONV_FUNC(wuff_int32_to_int24)
+{
+ size_t i;
+
+ if (head != 0)
+ {
+ memcpy(dst, src + 1 + offset, head);
+ src += 4;
+ dst += head;
+ }
+
+ for (i = 0; i < samples; i++)
+ {
+ memcpy(dst + i * 3, src + 1 + i * 4, 3);
+ }
+
+ if (tail != 0)
+ {
+ memcpy(dst + samples * 3, src + 1 + samples * 4, tail);
+ }
+}
+
+WUFF_CONV_FUNC(wuff_int32_to_int32)
+{
+ memcpy(dst, src + offset, samples * 4 + head + tail);
+}
+
+WUFF_CONV_FUNC(wuff_int32_to_float32)
+{
+ wuff_sint32 i32;
+ float f32;
+ size_t i;
+
+ if (head != 0)
+ {
+ memcpy(&i32, src, 4);
+ f32 = (float)((double)i32 / 2147483648.0);
+ memcpy(dst, (wuff_uint8 *)&f32 + offset, head);
+ src += 4;
+ dst += head;
+ }
+
+ for (i = 0; i < samples; i++)
+ {
+ memcpy(&i32, src + i * 4, 4);
+ f32 = (float)((double)i32 / 2147483648.0);
+ memcpy(dst + i * 4, &f32, 4);
+ }
+
+ if (tail != 0)
+ {
+ memcpy(&i32, src + samples * 4, 4);
+ f32 = (float)((double)i32 / 2147483648.0);
+ memcpy(dst + samples * 4, &f32, tail);
+ }
+}
+
+WUFF_CONV_FUNC(wuff_int32_to_float64)
+{
+ wuff_sint32 i32;
+ double f64;
+ size_t i;
+
+ if (head != 0)
+ {
+ memcpy(&i32, src, 4);
+ f64 = (double)i32 / 2147483648.0;
+ memcpy(dst, (wuff_uint8 *)&f64 + offset, head);
+ src += 4;
+ dst += head;
+ }
+
+ for (i = 0; i < samples; i++)
+ {
+ memcpy(&i32, src + i * 4, 4);
+ f64 = (double)i32 / 2147483648.0;
+ memcpy(dst + i * 8, &f64, 8);
+ }
+
+ if (tail != 0)
+ {
+ memcpy(&i32, src + samples * 4, 4);
+ f64 = (double)i32 / 2147483648.0;
+ memcpy(dst + samples * 8, &f64, tail);
+ }
+}
+
+/*
+ * float32 functions.
+ */
+
+WUFF_CONV_FUNC(wuff_float32_to_int8)
+{
+ float f32;
+ size_t i;
+ (void)offset; (void)head; (void)tail;
+
+ for (i = 0; i < samples; i++)
+ {
+ memcpy(&f32, src + i * 4, 4);
+ dst[i] = (wuff_uint8)((f32 * 127.5f) + 128.0f);
+ }
+}
+
+WUFF_CONV_FUNC(wuff_float32_to_int16)
+{
+ float f32;
+ wuff_sint16 i16;
+ size_t i;
+
+ if (head != 0)
+ {
+ memcpy(&f32, src, 4);
+ i16 = (wuff_sint16)(f32 * 32767.5f);
+ memcpy(dst, (wuff_uint8 *)&i16 + offset, head);
+ src += 4;
+ dst += head;
+ }
+
+ for (i = 0; i < samples; i++)
+ {
+ memcpy(&f32, src + i * 4, 4);
+ i16 = (wuff_sint16)(f32 * 32767.5f);
+ memcpy(dst + i * 2, &i16, 2);
+ }
+
+ if (tail != 0)
+ {
+ memcpy(&f32, src + i * 4, 4);
+ i16 = (wuff_sint16)(f32 * 32767.5f);
+ memcpy(dst + i * 2, &i16, tail);
+ }
+}
+
+WUFF_CONV_FUNC(wuff_float32_to_int24)
+{
+ float f32;
+ wuff_sint32 i24;
+ size_t i;
+
+ if (head != 0)
+ {
+ memcpy(&f32, src, 4);
+ i24 = (wuff_sint32)((double)f32 * 2147483647.5);
+ memcpy(dst, (wuff_uint8 *)&i24 + 1 + offset, head);
+ src += 4;
+ dst += head;
+ }
+
+ for (i = 0; i < samples; i++)
+ {
+ memcpy(&f32, src + i * 4, 4);
+ i24 = (wuff_sint32)((double)f32 * 2147483647.5);
+ memcpy(dst + i * 3, (wuff_uint8 *)&i24 + 1, 3);
+ }
+
+ if (tail != 0)
+ {
+ memcpy(&f32, src + samples * 4, 4);
+ i24 = (wuff_sint32)((double)f32 * 2147483647.5);
+ memcpy(dst + samples * 3, (wuff_uint8 *)&i24 + 1, tail);
+ }
+}
+
+WUFF_CONV_FUNC(wuff_float32_to_int32)
+{
+ float f32;
+ wuff_sint32 i32;
+ size_t i;
+
+ if (head != 0)
+ {
+ memcpy(&f32, src, 4);
+ i32 = (wuff_sint32)((double)f32 * 2147483647.5);
+ memcpy(dst, (wuff_uint8 *)&i32 + offset, head);
+ src += 4;
+ dst += head;
+ }
+
+ for (i = 0; i < samples; i++)
+ {
+ memcpy(&f32, src + i * 4, 4);
+ i32 = (wuff_sint32)((double)f32 * 2147483647.5);
+ memcpy(dst + i * 4, &i32, 4);
+ }
+
+ if (tail != 0)
+ {
+ memcpy(&f32, src + samples * 4, 4);
+ i32 = (wuff_sint32)((double)f32 * 2147483647.5);
+ memcpy(dst + samples * 4, &i32, tail);
+ }
+}
+
+WUFF_CONV_FUNC(wuff_float32_to_float32)
+{
+ memcpy(dst, src + offset, samples * 4 + head + tail);
+}
+
+WUFF_CONV_FUNC(wuff_float32_to_float64)
+{
+ float f32;
+ double f64;
+ size_t i;
+
+ if (head != 0)
+ {
+ memcpy(&f32, src, 4);
+ f64 = f32;
+ memcpy(dst, (wuff_uint8 *)&f64 + offset, head);
+ src += 4;
+ dst += head;
+ }
+
+ for (i = 0; i < samples; i++)
+ {
+ memcpy(&f32, src + i * 4, 4);
+ f64 = f32;
+ memcpy(dst + i * 8, &f64, 8);
+ }
+
+ if (tail != 0)
+ {
+ memcpy(&f32, src + samples * 4, 4);
+ f64 = f32;
+ memcpy(dst + samples * 8, &f64, tail);
+ }
+}
+
+/*
+ * float64 functions.
+ */
+
+WUFF_CONV_FUNC(wuff_float64_to_int8)
+{
+ double f64;
+ size_t i;
+ (void)offset; (void)head; (void)tail;
+
+ for (i = 0; i < samples; i++)
+ {
+ memcpy(&f64, src + i * 8, 8);
+ dst[i] = (wuff_uint8)((f64 * 127.5) + 128.0);
+ }
+}
+
+WUFF_CONV_FUNC(wuff_float64_to_int16)
+{
+ double f64;
+ wuff_sint16 i16;
+ size_t i;
+
+ if (head != 0)
+ {
+ memcpy(&f64, src, 8);
+ i16 = (wuff_sint16)(f64 * 32767.5);
+ memcpy(dst, (wuff_uint8 *)&i16 + offset, head);
+ src += 8;
+ dst += head;
+ }
+
+ for (i = 0; i < samples; i++)
+ {
+ memcpy(&f64, src + i * 8, 8);
+ i16 = (wuff_sint16)(f64 * 32767.5);
+ memcpy(dst + i * 2, &i16, 2);
+ }
+
+ if (tail != 0)
+ {
+ memcpy(&f64, src + i * 8, 8);
+ i16 = (wuff_sint16)(f64 * 32767.5);
+ memcpy(dst + i * 2, &i16, tail);
+ }
+}
+
+WUFF_CONV_FUNC(wuff_float64_to_int24)
+{
+ double f64;
+ wuff_sint32 i24;
+ size_t i;
+
+ if (head != 0)
+ {
+ memcpy(&f64, src, 8);
+ i24 = (wuff_sint32)(f64 * 2147483647.5);
+ memcpy(dst, (wuff_uint8 *)&i24 + 1 + offset, head);
+ src += 8;
+ dst += head;
+ }
+
+ for (i = 0; i < samples; i++)
+ {
+ memcpy(&f64, src + i * 8, 8);
+ i24 = (wuff_sint32)(f64 * 2147483647.5);
+ memcpy(dst + i * 3, (wuff_uint8 *)&i24 + 1, 3);
+ }
+
+ if (tail != 0)
+ {
+ memcpy(&f64, src + samples * 8, 8);
+ i24 = (wuff_sint32)(f64 * 2147483647.5);
+ memcpy(dst + samples * 3, (wuff_uint8 *)&i24 + 1, tail);
+ }
+}
+
+WUFF_CONV_FUNC(wuff_float64_to_int32)
+{
+ double f64;
+ wuff_sint32 i32;
+ size_t i;
+
+ if (head != 0)
+ {
+ memcpy(&f64, src, 8);
+ i32 = (wuff_sint32)(f64 * 2147483647.5);
+ memcpy(dst, (wuff_uint8 *)&i32 + offset, head);
+ src += 8;
+ dst += head;
+ }
+
+ for (i = 0; i < samples; i++)
+ {
+ memcpy(&f64, src + i * 8, 8);
+ i32 = (wuff_sint32)(f64 * 2147483647.5);
+ memcpy(dst + i * 4, &i32, 4);
+ }
+
+ if (tail != 0)
+ {
+ memcpy(&f64, src + samples * 8, 8);
+ i32 = (wuff_sint32)(f64 * 2147483647.5);
+ memcpy(dst + samples * 4, &i32, tail);
+ }
+}
+
+WUFF_CONV_FUNC(wuff_float64_to_float32)
+{
+ double f64;
+ float f32;
+ size_t i;
+
+ if (head != 0)
+ {
+ memcpy(&f64, src, 8);
+ f32 = (float)f64;
+ memcpy(dst, (wuff_uint8 *)&f32 + offset, head);
+ src += 8;
+ dst += head;
+ }
+
+ for (i = 0; i < samples; i++)
+ {
+ memcpy(&f64, src + i * 8, 8);
+ f32 = (float)f64;
+ memcpy(dst + i * 4, &f32, 4);
+ }
+
+ if (tail != 0)
+ {
+ memcpy(&f64, src + samples * 8, 8);
+ f32 = (float)f64;
+ memcpy(dst + samples * 4, &f32, tail);
+ }
+}
+
+WUFF_CONV_FUNC(wuff_float64_to_float64)
+{
+ memcpy(dst, src + offset, samples * 8 + head + tail);
+}
diff --git a/Source/3rdParty/Wuff/wuff_convert.h b/Source/3rdParty/Wuff/wuff_convert.h
new file mode 100644
index 0000000..280973d
--- /dev/null
+++ b/Source/3rdParty/Wuff/wuff_convert.h
@@ -0,0 +1,48 @@
+#ifndef WUFF_CONVERT_H
+#define WUFF_CONVERT_H
+
+#define WUFF_CONV_FUNC(name) WUFF_INTERN_API void name(wuff_uint8 * dst, wuff_uint8 * src, size_t samples, wuff_uint8 offset, wuff_uint8 head, wuff_uint8 tail)
+
+WUFF_CONV_FUNC(wuff_int8_to_int8);
+WUFF_CONV_FUNC(wuff_int8_to_int16);
+WUFF_CONV_FUNC(wuff_int8_to_int24);
+WUFF_CONV_FUNC(wuff_int8_to_int32);
+WUFF_CONV_FUNC(wuff_int8_to_float32);
+WUFF_CONV_FUNC(wuff_int8_to_float64);
+
+WUFF_CONV_FUNC(wuff_int16_to_int8);
+WUFF_CONV_FUNC(wuff_int16_to_int16);
+WUFF_CONV_FUNC(wuff_int16_to_int24);
+WUFF_CONV_FUNC(wuff_int16_to_int32);
+WUFF_CONV_FUNC(wuff_int16_to_float32);
+WUFF_CONV_FUNC(wuff_int16_to_float64);
+
+WUFF_CONV_FUNC(wuff_int24_to_int8);
+WUFF_CONV_FUNC(wuff_int24_to_int16);
+WUFF_CONV_FUNC(wuff_int24_to_int24);
+WUFF_CONV_FUNC(wuff_int24_to_int32);
+WUFF_CONV_FUNC(wuff_int24_to_float32);
+WUFF_CONV_FUNC(wuff_int24_to_float64);
+
+WUFF_CONV_FUNC(wuff_int32_to_int8);
+WUFF_CONV_FUNC(wuff_int32_to_int16);
+WUFF_CONV_FUNC(wuff_int32_to_int24);
+WUFF_CONV_FUNC(wuff_int32_to_int32);
+WUFF_CONV_FUNC(wuff_int32_to_float32);
+WUFF_CONV_FUNC(wuff_int32_to_float64);
+
+WUFF_CONV_FUNC(wuff_float32_to_int8);
+WUFF_CONV_FUNC(wuff_float32_to_int16);
+WUFF_CONV_FUNC(wuff_float32_to_int24);
+WUFF_CONV_FUNC(wuff_float32_to_int32);
+WUFF_CONV_FUNC(wuff_float32_to_float32);
+WUFF_CONV_FUNC(wuff_float32_to_float64);
+
+WUFF_CONV_FUNC(wuff_float64_to_int8);
+WUFF_CONV_FUNC(wuff_float64_to_int16);
+WUFF_CONV_FUNC(wuff_float64_to_int24);
+WUFF_CONV_FUNC(wuff_float64_to_int32);
+WUFF_CONV_FUNC(wuff_float64_to_float32);
+WUFF_CONV_FUNC(wuff_float64_to_float64);
+
+#endif /* WUFF_CONVERT_H */
diff --git a/Source/3rdParty/Wuff/wuff_internal.c b/Source/3rdParty/Wuff/wuff_internal.c
new file mode 100644
index 0000000..e481332
--- /dev/null
+++ b/Source/3rdParty/Wuff/wuff_internal.c
@@ -0,0 +1,540 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "wuff_config.h"
+#include "wuff.h"
+#include "wuff_internal.h"
+#include "wuff_convert.h"
+
+
+wuff_sint32 wuff_setup(struct wuff_handle * handle)
+{
+ wuff_sint32 wuff_status;
+
+ if (handle == NULL)
+ return WUFF_INVALID_PARAM;
+
+ wuff_status = wuff_init_stream(handle);
+ WUFF_STATUS_BAIL()
+
+ /* Allocating the buffer for the handle requires information from the stream. */
+ wuff_status = wuff_buffer_alloc(handle);
+ WUFF_STATUS_BAIL()
+
+ /* The output format defaults to the stream format. */
+ wuff_status = wuff_format(handle, handle->stream.format);
+ WUFF_STATUS_BAIL()
+
+ return WUFF_SUCCESS;
+}
+
+wuff_sint32 wuff_cleanup(struct wuff_handle * handle)
+{
+ if (handle == NULL)
+ return WUFF_INVALID_PARAM;
+
+ if (handle->buffer.data != NULL)
+ wuff_free(handle->buffer.data);
+ wuff_free(handle);
+
+ return WUFF_SUCCESS;
+}
+
+wuff_sint32 wuff_set_output_format(struct wuff_handle * handle, wuff_uint16 format)
+{
+ wuff_uint16 bits;
+ wuff_uint16 stream_format;
+
+ if (handle == NULL)
+ return WUFF_INVALID_PARAM;
+ else if (format >= WUFF_FORMAT_MAX)
+ return WUFF_FORMAT_UNSUPPORTED;
+
+ stream_format = handle->stream.format;
+
+ switch (format)
+ {
+ case WUFF_FORMAT_PCM_U8:
+ bits = 8;
+ switch (stream_format)
+ {
+ case WUFF_FORMAT_PCM_U8:
+ handle->output.function = wuff_int8_to_int8;
+ break;
+ case WUFF_FORMAT_PCM_S16:
+ handle->output.function = wuff_int16_to_int8;
+ break;
+ case WUFF_FORMAT_PCM_S24:
+ handle->output.function = wuff_int24_to_int8;
+ break;
+ case WUFF_FORMAT_PCM_S32:
+ handle->output.function = wuff_int32_to_int8;
+ break;
+ case WUFF_FORMAT_IEEE_FLOAT_32:
+ handle->output.function = wuff_float32_to_int8;
+ break;
+ case WUFF_FORMAT_IEEE_FLOAT_64:
+ handle->output.function = wuff_float64_to_int8;
+ break;
+ }
+ break;
+ case WUFF_FORMAT_PCM_S16:
+ bits = 16;
+ switch (stream_format)
+ {
+ case WUFF_FORMAT_PCM_U8:
+ handle->output.function = wuff_int8_to_int16;
+ break;
+ case WUFF_FORMAT_PCM_S16:
+ handle->output.function = wuff_int16_to_int16;
+ break;
+ case WUFF_FORMAT_PCM_S24:
+ handle->output.function = wuff_int24_to_int16;
+ break;
+ case WUFF_FORMAT_PCM_S32:
+ handle->output.function = wuff_int32_to_int16;
+ break;
+ case WUFF_FORMAT_IEEE_FLOAT_32:
+ handle->output.function = wuff_float32_to_int16;
+ break;
+ case WUFF_FORMAT_IEEE_FLOAT_64:
+ handle->output.function = wuff_float64_to_int16;
+ break;
+ }
+ break;
+ case WUFF_FORMAT_PCM_S24:
+ bits = 24;
+ switch (stream_format)
+ {
+ case WUFF_FORMAT_PCM_U8:
+ handle->output.function = wuff_int8_to_int24;
+ break;
+ case WUFF_FORMAT_PCM_S16:
+ handle->output.function = wuff_int16_to_int24;
+ break;
+ case WUFF_FORMAT_PCM_S24:
+ handle->output.function = wuff_int24_to_int24;
+ break;
+ case WUFF_FORMAT_PCM_S32:
+ handle->output.function = wuff_int32_to_int24;
+ break;
+ case WUFF_FORMAT_IEEE_FLOAT_32:
+ handle->output.function = wuff_float32_to_int24;
+ break;
+ case WUFF_FORMAT_IEEE_FLOAT_64:
+ handle->output.function = wuff_float64_to_int24;
+ break;
+ }
+ break;
+ case WUFF_FORMAT_PCM_S32:
+ bits = 32;
+ switch (stream_format)
+ {
+ case WUFF_FORMAT_PCM_U8:
+ handle->output.function = wuff_int8_to_int32;
+ break;
+ case WUFF_FORMAT_PCM_S16:
+ handle->output.function = wuff_int16_to_int32;
+ break;
+ case WUFF_FORMAT_PCM_S24:
+ handle->output.function = wuff_int24_to_int32;
+ break;
+ case WUFF_FORMAT_PCM_S32:
+ handle->output.function = wuff_int32_to_int32;
+ break;
+ case WUFF_FORMAT_IEEE_FLOAT_32:
+ handle->output.function = wuff_float32_to_int32;
+ break;
+ case WUFF_FORMAT_IEEE_FLOAT_64:
+ handle->output.function = wuff_float64_to_int32;
+ break;
+ }
+ break;
+ case WUFF_FORMAT_IEEE_FLOAT_32:
+ bits = 32;
+ switch (stream_format)
+ {
+ case WUFF_FORMAT_PCM_U8:
+ handle->output.function = wuff_int8_to_float32;
+ break;
+ case WUFF_FORMAT_PCM_S16:
+ handle->output.function = wuff_int16_to_float32;
+ break;
+ case WUFF_FORMAT_PCM_S24:
+ handle->output.function = wuff_int24_to_float32;
+ break;
+ case WUFF_FORMAT_PCM_S32:
+ handle->output.function = wuff_int32_to_float32;
+ break;
+ case WUFF_FORMAT_IEEE_FLOAT_32:
+ handle->output.function = wuff_float32_to_float32;
+ break;
+ case WUFF_FORMAT_IEEE_FLOAT_64:
+ handle->output.function = wuff_float64_to_float32;
+ break;
+ }
+ break;
+ case WUFF_FORMAT_IEEE_FLOAT_64:
+ bits = 64;
+ switch (stream_format)
+ {
+ case WUFF_FORMAT_PCM_U8:
+ handle->output.function = wuff_int8_to_float64;
+ break;
+ case WUFF_FORMAT_PCM_S16:
+ handle->output.function = wuff_int16_to_float64;
+ break;
+ case WUFF_FORMAT_PCM_S24:
+ handle->output.function = wuff_int24_to_float64;
+ break;
+ case WUFF_FORMAT_PCM_S32:
+ handle->output.function = wuff_int32_to_float64;
+ break;
+ case WUFF_FORMAT_IEEE_FLOAT_32:
+ handle->output.function = wuff_float32_to_float64;
+ break;
+ case WUFF_FORMAT_IEEE_FLOAT_64:
+ handle->output.function = wuff_float64_to_float64;
+ break;
+ }
+ break;
+ default:
+ return WUFF_FORMAT_UNSUPPORTED;
+ }
+
+ handle->output.format = format;
+ handle->output.bytes_per_sample = bits / 8;
+ handle->output.block_size = handle->stream.header.channels * (bits / 8);
+
+ return WUFF_SUCCESS;
+}
+
+wuff_sint32 wuff_check_bits(wuff_uint16 bits, wuff_uint16 * format)
+{
+ if (*format == WUFF_FORMAT_PCM)
+ {
+ switch (bits)
+ {
+ case 8:
+ *format = WUFF_FORMAT_PCM_U8;
+ break;
+ case 16:
+ *format = WUFF_FORMAT_PCM_S16;
+ break;
+ case 24:
+ *format = WUFF_FORMAT_PCM_S24;
+ break;
+ case 32:
+ *format = WUFF_FORMAT_PCM_S32;
+ break;
+ default:
+ return WUFF_FORMAT_UNSUPPORTED;
+ }
+ }
+ else if (*format == WUFF_FORMAT_IEEE_FLOAT)
+ {
+ switch (bits)
+ {
+ case 32:
+ *format = WUFF_FORMAT_IEEE_FLOAT_32;
+ break;
+ case 64:
+ *format = WUFF_FORMAT_IEEE_FLOAT_64;
+ break;
+ default:
+ return WUFF_FORMAT_UNSUPPORTED;
+ }
+ }
+ else
+ {
+ return WUFF_FORMAT_UNSUPPORTED;
+ }
+
+ return WUFF_SUCCESS;
+}
+
+size_t wuff_calculate_samples(size_t target_size, wuff_uint8 sample_size, wuff_uint8 * head, wuff_uint8 * tail)
+{
+ size_t samples = 0;
+
+ if (*head != 0)
+ {
+ if (target_size <= *head)
+ {
+ *head = (wuff_uint8)target_size;
+ *tail = 0;
+ return 1;
+ }
+ target_size -= *head;
+ ++samples;
+ }
+
+ samples = target_size / sample_size;
+ *tail = target_size % sample_size;
+ if (*tail != 0)
+ ++samples;
+ return samples;
+}
+
+wuff_sint32 wuff_init_stream(struct wuff_handle * handle)
+{
+ /* Allocate some space on the stack. */
+ /* No need to do dynamic allocation for simple header probing. */
+ wuff_uint8 buffer[WUFF_HEADER_FETCH_SIZE];
+ size_t buffer_size = WUFF_HEADER_FETCH_SIZE;
+ wuff_uint64 search_offset;
+ struct wuff_chunk_header chunk;
+ wuff_sint32 wuff_status;
+
+ wuff_status = handle->callback->read(handle->userdata, buffer, &buffer_size);
+ WUFF_STATUS_BAIL()
+ else if (buffer_size < WUFF_STREAM_MIN_SIZE)
+ return WUFF_STREAM_NOT_RIFF;
+
+ /* Check for RIFF signature. */
+ wuff_copy_chunk_header_data(&chunk, buffer);
+ if (chunk.id != WUFF_RIFF_CHUNK_ID)
+ return WUFF_STREAM_NOT_RIFF;
+ handle->stream.size = chunk.size;
+
+ /* Check for WAVE format. */
+ wuff_copy_chunk_header_data(&chunk, buffer + 8);
+ if (chunk.id != WUFF_WAVE_CHUNK_ID)
+ return WUFF_STREAM_NOT_WAVE;
+
+ /* Search fmt chunk. */
+ wuff_copy_chunk_header_data(&chunk, buffer + 12);
+ search_offset = 12;
+ if (chunk.id != WUFF_FORMAT_CHUNK_ID)
+ {
+ chunk.id = 0;
+ /* The fmt chunk must appear before the data chunk. */
+ wuff_status = wuff_search_chunk(handle, &chunk, &search_offset, WUFF_FORMAT_CHUNK_ID, WUFF_DATA_CHUNK_ID);
+ if (wuff_status == WUFF_STREAM_CHUNK_NOT_FOUND)
+ return WUFF_STREAM_FORMAT_CHUNK_MISSING;
+ else WUFF_STATUS_BAIL()
+
+ /* In case the fmt chunk is not the first chunk, align it on the stack buffer as if it were. */
+ buffer_size = WUFF_HEADER_FETCH_SIZE - 20;
+ wuff_status = handle->callback->read(handle->userdata, buffer + 20, &buffer_size);
+ WUFF_STATUS_BAIL()
+ /* EOF bail. */
+ else if (buffer_size < WUFF_HEADER_MIN_SIZE)
+ return WUFF_STREAM_INVALID;
+ }
+
+ /* Extract header information. */
+ handle->stream.header.size = chunk.size;
+ handle->stream.header.offset = search_offset + 8;
+ handle->stream.header.format = wuff_get_uint16(buffer + 20);
+ handle->stream.header.channels = wuff_get_uint16(buffer + 22);
+ handle->stream.header.sample_rate = wuff_get_uint32(buffer + 24);
+ handle->stream.header.bits_per_sample = wuff_get_uint16(buffer + 34);
+ handle->stream.header.bytes_per_sample = handle->stream.header.bits_per_sample / 8;
+ handle->stream.header.block_size = handle->stream.header.channels * handle->stream.header.bytes_per_sample;
+
+ /* Bail on invalid streams. */
+ if (handle->stream.header.channels == 0)
+ return WUFF_STREAM_ZERO_CHANNELS;
+ else if (handle->stream.header.sample_rate == 0)
+ return WUFF_STREAM_ZERO_SAMPLE_RATE;
+ else if (handle->stream.header.bits_per_sample == 0)
+ return WUFF_STREAM_ZERO_BITS_PER_SAMPLE;
+
+ /* Grab the format from the extended header. */
+ if (handle->stream.header.size > WUFF_HEADER_MIN_SIZE && wuff_get_uint16(buffer + 36) == 22)
+ {
+ if (handle->stream.header.format == WUFF_FORMAT_EXTENSIBLE)
+ handle->stream.header.format = wuff_get_uint16(buffer + 44);
+ }
+
+ /* The check if this format is actually supported. */
+ handle->stream.format = handle->stream.header.format;
+ wuff_status = wuff_check_bits(handle->stream.header.bits_per_sample, &handle->stream.format);
+ WUFF_STATUS_BAIL()
+
+ /* The search for the data chunk begins. */
+ wuff_copy_chunk_header_data(&chunk, buffer + 20 + handle->stream.header.size);
+ search_offset = handle->stream.header.offset + handle->stream.header.size;
+ wuff_status = wuff_search_chunk(handle, &chunk, &search_offset, WUFF_DATA_CHUNK_ID, 0);
+ if (wuff_status == WUFF_STREAM_CHUNK_NOT_FOUND)
+ return WUFF_STREAM_DATA_CHUNK_MISSING;
+ else WUFF_STATUS_BAIL()
+
+ handle->stream.data.size = chunk.size;
+ handle->stream.data.offset = search_offset + 8;
+ handle->stream.length = handle->stream.data.size / handle->stream.header.channels / handle->stream.header.bytes_per_sample;
+ handle->stream.position = 0;
+
+ return WUFF_SUCCESS;
+}
+
+wuff_sint32 wuff_search_chunk(struct wuff_handle * handle, struct wuff_chunk_header * chunk, wuff_uint64 * offset, wuff_uint32 id, wuff_uint32 stop_id)
+{
+ wuff_uint8 buffer[8];
+ wuff_uint64 search_offset;
+ size_t buffer_size;
+ wuff_sint32 wuff_status = 0;
+
+ if (chunk->id != 0 && chunk->id == id)
+ return WUFF_SUCCESS;
+
+ /* Copy the current file position. */
+ search_offset = *offset;
+
+ while (wuff_status >= 0)
+ {
+ search_offset += 8 + chunk->size;
+ /* FIXME: Non-compliant RIFFs may not pad to WORD alignment. What now? */
+ if (search_offset & 1)
+ search_offset++;
+
+ wuff_status = handle->callback->seek(handle->userdata, search_offset);
+ WUFF_STATUS_BAIL()
+ /*else if (wuff_status == WUFF_CALLBACK_EOF)
+ return WUFF_STREAM_CHUNK_NOT_FOUND;*/
+
+ buffer_size = 8;
+ wuff_status = handle->callback->read(handle->userdata, buffer, &buffer_size);
+ WUFF_STATUS_BAIL()
+
+ wuff_copy_chunk_header_data(chunk, buffer);
+ /* Bail if we're at the EOF or the stop id. */
+ if (buffer_size < 8 || (stop_id != 0 && chunk->id == stop_id))
+ return WUFF_STREAM_CHUNK_NOT_FOUND;
+ else if (chunk->id == id)
+ break;
+ }
+
+ /* Report chunk offset. */
+ *offset = search_offset;
+
+ return WUFF_SUCCESS;
+}
+
+wuff_sint32 wuff_buffer_alloc(struct wuff_handle * handle)
+{
+ wuff_sint32 wuff_status;
+
+ if (handle == NULL)
+ return WUFF_INVALID_PARAM;
+
+ /* Try to allocate a buffer for 0.25 seconds, but clamp at some minimum and maximum value. */
+ handle->buffer.size = handle->stream.header.sample_rate * handle->stream.header.block_size / 4;
+ if (handle->buffer.size < WUFF_BUFFER_MIN_SIZE)
+ handle->buffer.size = WUFF_BUFFER_MIN_SIZE;
+ else if (handle->buffer.size > WUFF_BUFFER_MAX_SIZE)
+ handle->buffer.size = WUFF_BUFFER_MAX_SIZE;
+
+ handle->buffer.data = wuff_alloc(handle->buffer.size);
+ if (handle->buffer.data == NULL)
+ return WUFF_MEMALLOC_ERROR;
+
+ /* Just in case, let's null the offsets. */
+ wuff_status = wuff_buffer_clear(handle);
+ WUFF_STATUS_BAIL()
+
+ return WUFF_SUCCESS;
+}
+
+wuff_sint32 wuff_buffer_clear(struct wuff_handle * handle)
+{
+ wuff_uint64 position;
+ wuff_sint32 wuff_status;
+
+ if (handle == NULL)
+ return WUFF_INVALID_PARAM;
+
+ wuff_status = handle->callback->tell(handle->userdata, &position);
+ WUFF_STATUS_BAIL()
+
+ if (position < handle->stream.data.offset || position > handle->stream.data.offset + handle->stream.data.size)
+ return WUFF_BUFFER_INVALID_STREAM_POSITION;
+
+ handle->buffer.bytes_left = handle->stream.data.size - (position - handle->stream.data.offset);
+ handle->buffer.offset = 0;
+ handle->buffer.end = 0;
+
+ return WUFF_SUCCESS;
+}
+
+wuff_sint32 wuff_buffer_fill(struct wuff_handle * handle)
+{
+ size_t bytes_in_buffer;
+ size_t bytes_to_read;
+ wuff_sint32 wuff_status;
+
+ if (handle == NULL)
+ return WUFF_INVALID_PARAM;
+
+ /* Check if there are bytes in the buffer and move them to the start of the buffer. */
+ /* Probably not the most efficient way. Think on it some more! */
+ bytes_in_buffer = handle->buffer.end - handle->buffer.offset;
+
+ if (bytes_in_buffer == handle->buffer.size)
+ return WUFF_SUCCESS;
+ else if (bytes_in_buffer > 0)
+ memmove(handle->buffer.data, handle->buffer.data + handle->buffer.offset, bytes_in_buffer);
+
+ bytes_to_read = handle->buffer.size - bytes_in_buffer;
+ if (bytes_to_read > handle->buffer.bytes_left)
+ bytes_to_read = (size_t)handle->buffer.bytes_left;
+
+ wuff_status = handle->callback->read(handle->userdata, handle->buffer.data + bytes_in_buffer, &bytes_to_read);
+ WUFF_STATUS_BAIL()
+
+ handle->buffer.offset = 0;
+ handle->buffer.end = bytes_in_buffer + bytes_to_read;
+ handle->buffer.bytes_left -= bytes_to_read;
+
+ return WUFF_SUCCESS;
+}
+
+wuff_sint32 wuff_buffer_release(struct wuff_handle * handle, size_t samples)
+{
+ size_t size;
+
+ if (handle == NULL)
+ return WUFF_INVALID_PARAM;
+
+ size = samples * handle->stream.header.bytes_per_sample;
+
+ /* Check for an attempt to release more samples than the buffer could hold. */
+ /* "This should never happen." Let's throw an error anyway in case.*/
+ if (size > handle->buffer.end - handle->buffer.offset)
+ return WUFF_BUFFER_INVALID_SIZE;
+
+ handle->buffer.offset += size;
+
+ return WUFF_SUCCESS;
+}
+
+wuff_sint32 wuff_buffer_request(struct wuff_handle * handle, wuff_uint8 ** buffer, size_t * samples)
+{
+ size_t request_samples = *samples;
+ size_t buffer_samples, size;
+ size_t bps = handle->stream.header.bytes_per_sample;
+ wuff_sint32 wuff_status;
+
+ if (handle == NULL || buffer == NULL || samples == NULL)
+ return WUFF_INVALID_PARAM;
+
+ /* Fill the buffer some more if the requested size is bigger than the current data in the buffer. */
+ size = request_samples * bps;
+ if (size > handle->buffer.end - handle->buffer.offset)
+ {
+ wuff_status = wuff_buffer_fill(handle);
+ WUFF_STATUS_BAIL()
+ }
+
+ buffer_samples = (handle->buffer.end - handle->buffer.offset) / bps;
+
+ /* Report sample count change. */
+ if (buffer_samples < request_samples)
+ *samples = buffer_samples;
+
+ /* Report sample buffer start. */
+ *buffer = handle->buffer.data + handle->buffer.offset;
+
+ return WUFF_SUCCESS;
+}
diff --git a/Source/3rdParty/Wuff/wuff_internal.h b/Source/3rdParty/Wuff/wuff_internal.h
new file mode 100644
index 0000000..2679cdb
--- /dev/null
+++ b/Source/3rdParty/Wuff/wuff_internal.h
@@ -0,0 +1,171 @@
+#ifndef WUFF_INTERNAL_H
+#define WUFF_INTERNAL_H
+
+#define WUFF_BUFFER_MIN_SIZE 4096
+#define WUFF_BUFFER_MAX_SIZE 2097152
+#define WUFF_STREAM_MIN_SIZE 36
+#define WUFF_HEADER_MIN_SIZE 16
+#define WUFF_HEADER_FETCH_SIZE 80
+
+#define WUFF_FORMAT_PCM 1
+#define WUFF_FORMAT_IEEE_FLOAT 3
+#define WUFF_FORMAT_EXTENSIBLE 0xFFFE
+
+
+#define WUFF_RIFF_CHUNK_ID wuff_get_chunk_id("RIFF")
+#define WUFF_WAVE_CHUNK_ID wuff_get_chunk_id("WAVE")
+#define WUFF_FORMAT_CHUNK_ID wuff_get_chunk_id("fmt ")
+#define WUFF_DATA_CHUNK_ID wuff_get_chunk_id("data")
+
+#define WUFF_STATUS_BAIL() if (wuff_status < 0) return wuff_status;
+
+
+static WUFF_INLINE wuff_uint32 wuff_get_uint32(wuff_uint8 * data)
+{
+ return data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24);
+}
+
+static WUFF_INLINE wuff_uint16 wuff_get_uint16(wuff_uint8 * data)
+{
+ return data[0] + (data[1] << 8);
+}
+
+struct wuff_chunk_header
+{
+ wuff_uint32 id;
+ wuff_uint32 size;
+};
+
+static WUFF_INLINE wuff_uint32 wuff_get_chunk_id(const char txt[5])
+{
+ const wuff_uint8 * id = (wuff_uint8*) txt;
+ wuff_uint32 int_id;
+ wuff_uint8 * id_bytes = (wuff_uint8 *)&int_id;
+ id_bytes[0] = id[0];
+ id_bytes[1] = id[1];
+ id_bytes[2] = id[2];
+ id_bytes[3] = id[3];
+
+ return int_id;
+}
+
+static WUFF_INLINE void wuff_copy_chunk_header_data(struct wuff_chunk_header * chunk, wuff_uint8 * data)
+{
+ wuff_uint8 * id = (wuff_uint8 *)&chunk->id;
+ id[0] = data[0];
+ id[1] = data[1];
+ id[2] = data[2];
+ id[3] = data[3];
+
+ chunk->size = wuff_get_uint32(data + 4);
+}
+
+struct wuff_stream_header
+{
+ wuff_uint64 size;
+ wuff_uint64 offset;
+
+ wuff_uint16 format;
+ wuff_uint16 channels;
+ wuff_uint32 sample_rate;
+ wuff_uint16 bits_per_sample;
+ wuff_uint16 bytes_per_sample;
+ size_t block_size;
+};
+
+struct wuff_stream_data
+{
+ wuff_uint64 size;
+ wuff_uint64 offset;
+};
+
+struct wuff_buffer
+{
+ wuff_uint8 * data;
+ wuff_uint64 bytes_left;
+ size_t size;
+ size_t offset;
+ size_t end;
+};
+
+struct wuff_output
+{
+ wuff_uint16 format;
+ size_t bytes_per_sample;
+ size_t block_size;
+ size_t block_offset;
+ void (* function)(wuff_uint8 *, wuff_uint8 *, size_t, wuff_uint8, wuff_uint8, wuff_uint8);
+};
+
+struct wuff_stream
+{
+ wuff_uint64 size;
+ wuff_uint64 length;
+ wuff_uint16 format;
+
+ wuff_uint64 position;
+
+ struct wuff_stream_header header;
+ struct wuff_stream_data data;
+};
+
+struct wuff_handle
+{
+ struct wuff_stream stream;
+ struct wuff_buffer buffer;
+ struct wuff_output output;
+ struct wuff_callback * callback;
+ void * userdata;
+};
+
+
+/* Initializes the stream, allocates the buffer, and sets the output format. */
+/* Expects a nulled wuff_handle and the callbacks set and ready. */
+WUFF_INTERN_API wuff_sint32 wuff_setup(struct wuff_handle * handle);
+
+/* Cleans the stream up, frees the buffer and the wuff_handle. */
+WUFF_INTERN_API wuff_sint32 wuff_cleanup(struct wuff_handle * handle);
+
+/* Called by wuff_setup. Initializes the stream by reading the data from the */
+/* callbacks, searching for headers and stream information. */
+WUFF_INTERN_API wuff_sint32 wuff_init_stream(struct wuff_handle * handle);
+
+/* Searches for a specific chunk id and stops before another if it's not 0. */
+/* If the id in wuff_chunk_header is not 0, it will be checked too and if */
+/* they match, then the function will return immediately. */
+/* Expects offset to point to the file position of a chunk and */
+/* wuff_chunk_header to have the size of this chunk. */
+WUFF_INTERN_API wuff_sint32 wuff_search_chunk(struct wuff_handle * handle, struct wuff_chunk_header * chunk, wuff_uint64 * offset, wuff_uint32 id, wuff_uint32 stop_id);
+
+/* Sets the output struct of the stream to the new format. */
+WUFF_INTERN_API wuff_sint32 wuff_set_output_format(struct wuff_handle * handle, wuff_uint16);
+
+/* Checks if the number of bits per samples is supported and writes the */
+/* output identifier to the 16-bit integer. */
+WUFF_INTERN_API wuff_sint32 wuff_check_bits(wuff_uint16 bits, wuff_uint16 * format);
+
+/* Calculates the number of samples that have to be requested from the buffer */
+/* by also taking the truncated samples at the start and end into account. */
+/* The return value is the number of samples needed. */
+WUFF_INTERN_API size_t wuff_calculate_samples(size_t target_size, wuff_uint8 sample_size, wuff_uint8 * head, wuff_uint8 * tail);
+
+
+/* Allocates the buffer for the input stream. */
+/* Expects the stream to be initialized, as format information is needed. */
+WUFF_INTERN_API wuff_sint32 wuff_buffer_alloc(struct wuff_handle * handle);
+
+/* Fills the buffer with new data. */
+WUFF_INTERN_API wuff_sint32 wuff_buffer_fill(struct wuff_handle * handle);
+
+/* Marks all bytes in the buffer as free. */
+WUFF_INTERN_API wuff_sint32 wuff_buffer_clear(struct wuff_handle * handle);
+
+/* Requests samples and a pointer to them. */
+/* The number of samples may be lower than requested. */
+WUFF_INTERN_API wuff_sint32 wuff_buffer_request(struct wuff_handle * handle, wuff_uint8 ** buffer, size_t * samples);
+
+/* Releases the number of samples from the buffer. */
+WUFF_INTERN_API wuff_sint32 wuff_buffer_release(struct wuff_handle * handle, size_t samples);
+
+
+#endif /* WUFF_INTERNAL_H */
diff --git a/Source/3rdParty/Wuff/wuff_memory.c b/Source/3rdParty/Wuff/wuff_memory.c
new file mode 100644
index 0000000..eaffa4e
--- /dev/null
+++ b/Source/3rdParty/Wuff/wuff_memory.c
@@ -0,0 +1,17 @@
+#include <stdlib.h>
+
+#include "wuff_config.h"
+
+/* Default memory allocators. */
+/* They can be overridden with custom functions at build time. */
+#ifndef WUFF_MEMALLOC_OVERRIDE
+void * wuff_alloc(size_t size)
+{
+ return malloc(size);
+}
+
+void wuff_free(void * mem)
+{
+ free(mem);
+}
+#endif