aboutsummaryrefslogtreecommitdiff
path: root/src/external
diff options
context:
space:
mode:
authorRay <raysan5@gmail.com>2016-10-16 18:24:13 +0200
committerGitHub <noreply@github.com>2016-10-16 18:24:13 +0200
commita9315fc422a3a036891f50f0c2be5059c3db8b31 (patch)
tree9f5213dac656079e2163bc5d091200dc837672b8 /src/external
parent53056f3e7e84e18b8ebfc4a2ab2f7f1fbe7ae36c (diff)
parent1c05017548ea21dd1a44c31e9fc80b8700891f11 (diff)
downloadraylib-a9315fc422a3a036891f50f0c2be5059c3db8b31.tar.gz
raylib-a9315fc422a3a036891f50f0c2be5059c3db8b31.zip
Merge pull request #189 from raysan5/develop
Develop branch integration
Diffstat (limited to 'src/external')
-rw-r--r--src/external/OculusSDK/LibOVR/Include/OVR_CAPI.h151
-rw-r--r--src/external/OculusSDK/LibOVR/Include/OVR_CAPI_Audio.h4
-rw-r--r--src/external/OculusSDK/LibOVR/Include/OVR_CAPI_D3D.h3
-rw-r--r--src/external/OculusSDK/LibOVR/Include/OVR_CAPI_GL.h3
-rw-r--r--src/external/OculusSDK/LibOVR/Include/OVR_ErrorCode.h9
-rw-r--r--src/external/OculusSDK/LibOVR/Include/OVR_Version.h2
-rw-r--r--src/external/OculusSDK/LibOVR/LibOVRRT32_1.dllbin1023952 -> 1044944 bytes
-rw-r--r--src/external/dr_flac.h4395
-rw-r--r--src/external/jar_mod.h6
-rw-r--r--src/external/jar_xm.h62
-rw-r--r--src/external/lua/include/lauxlib.h256
-rw-r--r--src/external/lua/include/lua.h486
-rw-r--r--src/external/lua/include/lua.hpp9
-rw-r--r--src/external/lua/include/luaconf.h769
-rw-r--r--src/external/lua/include/lualib.h58
-rw-r--r--src/external/lua/lib/liblua53.abin0 -> 322424 bytes
-rw-r--r--src/external/lua/lib/liblua53dll.abin0 -> 91416 bytes
-rw-r--r--src/external/openal_soft/include/AL/alext.h5
-rw-r--r--src/external/openal_soft/lib/win32/libOpenAL32.abin0 -> 2226842 bytes
-rw-r--r--src/external/pthread/lib/pthreadGC2.dllbin0 -> 119888 bytes
20 files changed, 6125 insertions, 93 deletions
diff --git a/src/external/OculusSDK/LibOVR/Include/OVR_CAPI.h b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI.h
index 53340478..eaabcf59 100644
--- a/src/external/OculusSDK/LibOVR/Include/OVR_CAPI.h
+++ b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI.h
@@ -271,6 +271,12 @@ typedef char ovrBool; ///< Boolean type
//-----------------------------------------------------------------------------------
// ***** Simple Math Structures
+/// A RGBA color with normalized float components.
+typedef struct OVR_ALIGNAS(4) ovrColorf_
+{
+ float r, g, b, a;
+} ovrColorf;
+
/// A 2D vector with integer components.
typedef struct OVR_ALIGNAS(4) ovrVector2i_
{
@@ -326,7 +332,7 @@ typedef struct OVR_ALIGNAS(4) ovrPosef_
/// A full pose (rigid body) configuration with first and second derivatives.
///
/// Body refers to any object for which ovrPoseStatef is providing data.
-/// It can be the HMD, Touch controller, sensor or something else. The context
+/// It can be the HMD, Touch controller, sensor or something else. The context
/// depends on the usage of the struct.
typedef struct OVR_ALIGNAS(8) ovrPoseStatef_
{
@@ -687,7 +693,7 @@ typedef enum ovrTextureFormat_
///
typedef enum ovrTextureMiscFlags_
{
- ovrTextureMisc_None,
+ ovrTextureMisc_None,
/// DX only: The underlying texture is created with a TYPELESS equivalent of the
/// format specified in the texture desc. The SDK will still access the
@@ -745,12 +751,12 @@ typedef struct ovrMirrorTextureData* ovrMirrorTexture;
//-----------------------------------------------------------------------------------
/// Describes button input types.
-/// Button inputs are combined; that is they will be reported as pressed if they are
+/// Button inputs are combined; that is they will be reported as pressed if they are
/// pressed on either one of the two devices.
/// The ovrButton_Up/Down/Left/Right map to both XBox D-Pad and directional buttons.
/// The ovrButton_Enter and ovrButton_Return map to Start and Back controller buttons, respectively.
typedef enum ovrButton_
-{
+{
ovrButton_A = 0x00000001,
ovrButton_B = 0x00000002,
ovrButton_RThumb = 0x00000004,
@@ -758,7 +764,7 @@ typedef enum ovrButton_
ovrButton_X = 0x00000100,
ovrButton_Y = 0x00000200,
- ovrButton_LThumb = 0x00000400,
+ ovrButton_LThumb = 0x00000400,
ovrButton_LShoulder = 0x00000800,
// Navigation through DPad.
@@ -770,7 +776,7 @@ typedef enum ovrButton_
ovrButton_Back = 0x00200000, // Back on Xbox controller.
ovrButton_VolUp = 0x00400000, // only supported by Remote.
ovrButton_VolDown = 0x00800000, // only supported by Remote.
- ovrButton_Home = 0x01000000,
+ ovrButton_Home = 0x01000000,
ovrButton_Private = ovrButton_VolUp | ovrButton_VolDown | ovrButton_Home,
// Bit mask of all buttons on the right Touch controller
@@ -807,7 +813,7 @@ typedef enum ovrTouch_
// Bit mask of all the button touches on the left controller
ovrTouch_LButtonMask = ovrTouch_X | ovrTouch_Y | ovrTouch_LThumb | ovrTouch_LThumbRest | ovrTouch_LIndexTrigger,
- // Finger pose state
+ // Finger pose state
// Derived internally based on distance, proximity to sensors and filtering.
ovrTouch_RIndexPointing = 0x00000020,
ovrTouch_RThumbUp = 0x00000040,
@@ -883,11 +889,20 @@ typedef struct ovrHapticsPlaybackState_
int SamplesQueued;
} ovrHapticsPlaybackState;
+/// Position tracked devices
+typedef enum ovrTrackedDeviceType_
+{
+ ovrTrackedDevice_HMD = 0x0001,
+ ovrTrackedDevice_LTouch = 0x0002,
+ ovrTrackedDevice_RTouch = 0x0004,
+ ovrTrackedDevice_Touch = 0x0006,
+ ovrTrackedDevice_All = 0xFFFF,
+} ovrTrackedDeviceType;
/// Provides names for the left and right hand array indexes.
///
/// \see ovrInputState, ovrTrackingState
-///
+///
typedef enum ovrHandType_
{
ovrHand_Left = 0,
@@ -903,27 +918,43 @@ typedef enum ovrHandType_
/// their inputs are combined.
typedef struct ovrInputState_
{
- // System type when the controller state was last updated.
+ /// System type when the controller state was last updated.
double TimeInSeconds;
- // Values for buttons described by ovrButton.
+ /// Values for buttons described by ovrButton.
unsigned int Buttons;
- // Touch values for buttons and sensors as described by ovrTouch.
+ /// Touch values for buttons and sensors as described by ovrTouch.
unsigned int Touches;
-
- // Left and right finger trigger values (ovrHand_Left and ovrHand_Right), in the range 0.0 to 1.0f.
+
+ /// Left and right finger trigger values (ovrHand_Left and ovrHand_Right), in the range 0.0 to 1.0f.
+ /// Returns 0 if the value would otherwise be less than 0.1176, for ovrControllerType_XBox
float IndexTrigger[ovrHand_Count];
-
- // Left and right hand trigger values (ovrHand_Left and ovrHand_Right), in the range 0.0 to 1.0f.
+
+ /// Left and right hand trigger values (ovrHand_Left and ovrHand_Right), in the range 0.0 to 1.0f.
float HandTrigger[ovrHand_Count];
- // Horizontal and vertical thumbstick axis values (ovrHand_Left and ovrHand_Right), in the range -1.0f to 1.0f.
+ /// Horizontal and vertical thumbstick axis values (ovrHand_Left and ovrHand_Right), in the range -1.0f to 1.0f.
+ /// Returns a deadzone (value 0) per each axis if the value on that axis would otherwise have been between -.2746 to +.2746, for ovrControllerType_XBox
ovrVector2f Thumbstick[ovrHand_Count];
- // The type of the controller this state is for.
+ /// The type of the controller this state is for.
ovrControllerType ControllerType;
-
+
+ /// Left and right finger trigger values (ovrHand_Left and ovrHand_Right), in the range 0.0 to 1.0f.
+ /// Does not apply a deadzone
+ /// Added in 1.7
+ float IndexTriggerNoDeadzone[ovrHand_Count];
+
+ /// Left and right hand trigger values (ovrHand_Left and ovrHand_Right), in the range 0.0 to 1.0f.
+ /// Does not apply a deadzone
+ /// Added in 1.7
+ float HandTriggerNoDeadzone[ovrHand_Count];
+
+ /// Horizontal and vertical thumbstick axis values (ovrHand_Left and ovrHand_Right), in the range -1.0f to 1.0f
+ /// Does not apply a deadzone
+ /// Added in 1.7
+ ovrVector2f ThumbstickNoDeadzone[ovrHand_Count];
} ovrInputState;
@@ -996,8 +1027,8 @@ typedef struct OVR_ALIGNAS(8) ovrInitParams_
/// Use NULL to specify no log callback.
ovrLogCallback LogCallback;
- /// User-supplied data which is passed as-is to LogCallback. Typically this
- /// is used to store an application-specific pointer which is read in the
+ /// User-supplied data which is passed as-is to LogCallback. Typically this
+ /// is used to store an application-specific pointer which is read in the
/// callback function.
uintptr_t UserData;
@@ -1014,6 +1045,7 @@ typedef struct OVR_ALIGNAS(8) ovrInitParams_
extern "C" {
#endif
+#if !defined(OVR_EXPORTING_CAPI)
// -----------------------------------------------------------------------------------
// ***** API Interfaces
@@ -1026,7 +1058,7 @@ extern "C" {
/// followed by a call to ovr_Shutdown. ovr_Initialize calls are idempotent.
/// Calling ovr_Initialize twice does not require two matching calls to ovr_Shutdown.
/// If already initialized, the return value is ovr_Success.
-///
+///
/// LibOVRRT shared library search order:
/// -# Current working directory (often the same as the application directory).
/// -# Module directory (usually the same as the application directory,
@@ -1166,21 +1198,21 @@ OVR_PUBLIC_FUNCTION(ovrResult) ovr_IdentifyClient(const char* identity);
///
/// ovr_Initialize must have first been called in order for this to succeed, otherwise ovrHmdDesc::Type
/// will be reported as ovrHmd_None.
-///
+///
/// \param[in] session Specifies an ovrSession previously returned by ovr_Create, else NULL in which
/// case this function detects whether an HMD is present and returns its info if so.
///
-/// \return Returns an ovrHmdDesc. If the hmd is NULL and ovrHmdDesc::Type is ovrHmd_None then
+/// \return Returns an ovrHmdDesc. If the hmd is NULL and ovrHmdDesc::Type is ovrHmd_None then
/// no HMD is present.
///
OVR_PUBLIC_FUNCTION(ovrHmdDesc) ovr_GetHmdDesc(ovrSession session);
-/// Returns the number of sensors.
+/// Returns the number of sensors.
///
-/// The number of sensors may change at any time, so this function should be called before use
+/// The number of sensors may change at any time, so this function should be called before use
/// as opposed to once on startup.
-///
+///
/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
///
/// \return Returns unsigned int count.
@@ -1190,15 +1222,15 @@ OVR_PUBLIC_FUNCTION(unsigned int) ovr_GetTrackerCount(ovrSession session);
/// Returns a given sensor description.
///
-/// It's possible that sensor desc [0] may indicate a unconnnected or non-pose tracked sensor, but
+/// It's possible that sensor desc [0] may indicate a unconnnected or non-pose tracked sensor, but
/// sensor desc [1] may be connected.
///
/// ovr_Initialize must have first been called in order for this to succeed, otherwise the returned
/// trackerDescArray will be zero-initialized. The data returned by this function can change at runtime.
-///
+///
/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
-///
-/// \param[in] trackerDescIndex Specifies a sensor index. The valid indexes are in the range of 0 to
+///
+/// \param[in] trackerDescIndex Specifies a sensor index. The valid indexes are in the range of 0 to
/// the sensor count returned by ovr_GetTrackerCount.
///
/// \return Returns ovrTrackerDesc. An empty ovrTrackerDesc will be returned if trackerDescIndex is out of range.
@@ -1242,6 +1274,7 @@ OVR_PUBLIC_FUNCTION(ovrResult) ovr_Create(ovrSession* pSession, ovrGraphicsLuid*
///
OVR_PUBLIC_FUNCTION(void) ovr_Destroy(ovrSession session);
+#endif // !defined(OVR_EXPORTING_CAPI)
/// Specifies status information for the current session.
///
@@ -1253,10 +1286,11 @@ typedef struct ovrSessionStatus_
ovrBool HmdPresent; ///< True if an HMD is present.
ovrBool HmdMounted; ///< True if the HMD is on the user's head.
ovrBool DisplayLost; ///< True if the session is in a display-lost state. See ovr_SubmitFrame.
- ovrBool ShouldQuit; ///< True if the application should initiate shutdown.
+ ovrBool ShouldQuit; ///< True if the application should initiate shutdown.
ovrBool ShouldRecenter; ///< True if UX has requested re-centering. Must call ovr_ClearShouldRecenterFlag or ovr_RecenterTrackingOrigin.
}ovrSessionStatus;
+#if !defined(OVR_EXPORTING_CAPI)
/// Returns status information for the application.
///
@@ -1293,7 +1327,7 @@ OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetSessionStatus(ovrSession session, ovrSessi
///
/// When the tracking origin is changed, all of the calls that either provide
/// or accept ovrPosef will use the new tracking origin provided.
-///
+///
/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
/// \param[in] origin Specifies an ovrTrackingOrigin to be used for all ovrPosef
///
@@ -1305,7 +1339,7 @@ OVR_PUBLIC_FUNCTION(ovrResult) ovr_SetTrackingOriginType(ovrSession session, ovr
/// Gets the tracking origin state
-///
+///
/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
///
/// \return Returns the ovrTrackingOrigin that was either set by default, or previous set by the application.
@@ -1319,9 +1353,9 @@ OVR_PUBLIC_FUNCTION(ovrTrackingOrigin) ovr_GetTrackingOriginType(ovrSession sess
/// This resets the (x,y,z) positional components and the yaw orientation component.
/// The Roll and pitch orientation components are always determined by gravity and cannot
/// be redefined. All future tracking will report values relative to this new reference position.
-/// If you are using ovrTrackerPoses then you will need to call ovr_GetTrackerPose after
+/// If you are using ovrTrackerPoses then you will need to call ovr_GetTrackerPose after
/// this, because the sensor position(s) will change as a result of this.
-///
+///
/// The headset cannot be facing vertically upward or downward but rather must be roughly
/// level otherwise this function will fail with ovrError_InvalidHeadsetOrientation.
///
@@ -1343,7 +1377,7 @@ OVR_PUBLIC_FUNCTION(ovrResult) ovr_RecenterTrackingOrigin(ovrSession session);
/// Clears the ShouldRecenter status bit in ovrSessionStatus.
///
-/// Clears the ShouldRecenter status bit in ovrSessionStatus, allowing further recenter
+/// Clears the ShouldRecenter status bit in ovrSessionStatus, allowing further recenter
/// requests to be detected. Since this is automatically done by ovr_RecenterTrackingOrigin,
/// this is only needs to be called when application is doing its own re-centering.
OVR_PUBLIC_FUNCTION(void) ovr_ClearShouldRecenterFlag(ovrSession session);
@@ -1444,11 +1478,11 @@ OVR_PUBLIC_FUNCTION(ovrResult) ovr_SubmitControllerVibration(ovrSession session,
/// \param[in] outState State of the haptics engine.
/// \return Returns ovrSuccess upon success.
/// \see ovrHapticsPlaybackState
-///
+///
OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetControllerVibrationState(ovrSession session, ovrControllerType controllerType, ovrHapticsPlaybackState* outState);
-///@}
+#endif // !defined(OVR_EXPORTING_CAPI)
//-------------------------------------------------------------------------------------
// @name Layers
@@ -1672,7 +1706,7 @@ typedef union ovrLayer_Union_
//@}
-
+#if !defined(OVR_EXPORTING_CAPI)
/// @name SDK Distortion Rendering
///
@@ -1695,7 +1729,7 @@ typedef union ovrLayer_Union_
/// \param[in] chain Specifies the ovrTextureSwapChain for which the length should be retrieved.
/// \param[out] out_Length Returns the number of buffers in the specified chain.
///
-/// \return Returns an ovrResult for which OVR_SUCCESS(result) is false upon error.
+/// \return Returns an ovrResult for which OVR_SUCCESS(result) is false upon error.
///
/// \see ovr_CreateTextureSwapChainDX, ovr_CreateTextureSwapChainGL
///
@@ -1707,7 +1741,7 @@ OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetTextureSwapChainLength(ovrSession session,
/// \param[in] chain Specifies the ovrTextureSwapChain for which the index should be retrieved.
/// \param[out] out_Index Returns the current (free) index in specified chain.
///
-/// \return Returns an ovrResult for which OVR_SUCCESS(result) is false upon error.
+/// \return Returns an ovrResult for which OVR_SUCCESS(result) is false upon error.
///
/// \see ovr_CreateTextureSwapChainDX, ovr_CreateTextureSwapChainGL
///
@@ -1719,7 +1753,7 @@ OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetTextureSwapChainCurrentIndex(ovrSession se
/// \param[in] chain Specifies the ovrTextureSwapChain for which the description should be retrieved.
/// \param[out] out_Desc Returns the description of the specified chain.
///
-/// \return Returns an ovrResult for which OVR_SUCCESS(result) is false upon error.
+/// \return Returns an ovrResult for which OVR_SUCCESS(result) is false upon error.
///
/// \see ovr_CreateTextureSwapChainDX, ovr_CreateTextureSwapChainGL
///
@@ -1736,7 +1770,7 @@ OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetTextureSwapChainDesc(ovrSession session, o
/// it will synchronize with the app's graphics context and pick up the submitted index, opening up
/// room in the swap chain for further commits.
///
-/// \return Returns an ovrResult for which OVR_SUCCESS(result) is false upon error.
+/// \return Returns an ovrResult for which OVR_SUCCESS(result) is false upon error.
/// Failures include but aren't limited to:
/// - ovrError_TextureSwapChainFull: ovr_CommitTextureSwapChain was called too many times on a texture swapchain without calling submit to use the chain.
///
@@ -1864,7 +1898,7 @@ OVR_PUBLIC_FUNCTION(ovrEyeRenderDesc) ovr_GetRenderDesc(ovrSession session,
/// destroyed (ovr_Destroy) and recreated (ovr_Create), and new resources need to be created
/// (ovr_CreateTextureSwapChainXXX). The application's existing private graphics resources do not
/// need to be recreated unless the new ovr_Create call returns a different GraphicsLuid.
-/// - ovrError_TextureSwapChainInvalid: The ovrTextureSwapChain is in an incomplete or inconsistent state.
+/// - ovrError_TextureSwapChainInvalid: The ovrTextureSwapChain is in an incomplete or inconsistent state.
/// Ensure ovr_CommitTextureSwapChain was called at least once first.
///
/// \see ovr_GetPredictedDisplayTime, ovrViewScaleDesc, ovrLayerHeader
@@ -1874,7 +1908,7 @@ OVR_PUBLIC_FUNCTION(ovrResult) ovr_SubmitFrame(ovrSession session, long long fra
ovrLayerHeader const * const * layerPtrList, unsigned int layerCount);
///@}
-
+#endif // !defined(OVR_EXPORTING_CAPI)
//-------------------------------------------------------------------------------------
/// @name Frame Timing
@@ -1882,26 +1916,28 @@ OVR_PUBLIC_FUNCTION(ovrResult) ovr_SubmitFrame(ovrSession session, long long fra
//@{
+#if !defined(OVR_EXPORTING_CAPI)
+
/// Gets the time of the specified frame midpoint.
///
-/// Predicts the time at which the given frame will be displayed. The predicted time
-/// is the middle of the time period during which the corresponding eye images will
-/// be displayed.
+/// Predicts the time at which the given frame will be displayed. The predicted time
+/// is the middle of the time period during which the corresponding eye images will
+/// be displayed.
///
/// The application should increment frameIndex for each successively targeted frame,
-/// and pass that index to any relevent OVR functions that need to apply to the frame
+/// and pass that index to any relevant OVR functions that need to apply to the frame
/// identified by that index.
///
/// This function is thread-safe and allows for multiple application threads to target
/// their processing to the same displayed frame.
-///
+///
/// In the even that prediction fails due to various reasons (e.g. the display being off
/// or app has yet to present any frames), the return value will be current CPU time.
-///
+///
/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
/// \param[in] frameIndex Identifies the frame the caller wishes to target.
/// A value of zero returns the next frame index.
-/// \return Returns the absolute frame midpoint time for the given frameIndex.
+/// \return Returns the absolute frame midpoint time for the given frameIndex.
/// \see ovr_GetTimeInSeconds
///
OVR_PUBLIC_FUNCTION(double) ovr_GetPredictedDisplayTime(ovrSession session, long long frameIndex);
@@ -1917,6 +1953,7 @@ OVR_PUBLIC_FUNCTION(double) ovr_GetPredictedDisplayTime(ovrSession session, long
///
OVR_PUBLIC_FUNCTION(double) ovr_GetTimeInSeconds();
+#endif // !defined(OVR_EXPORTING_CAPI)
/// Performance HUD enables the HMD user to see information critical to
/// the real-time operation of the VR application such as latency timing,
@@ -1958,7 +1995,7 @@ typedef enum ovrLayerHudMode_
///@}
/// Debug HUD is provided to help developers gauge and debug the fidelity of their app's
-/// stereo rendering characteristics. Using the provided quad and crosshair guides,
+/// stereo rendering characteristics. Using the provided quad and crosshair guides,
/// the developer can verify various aspects such as VR tracking units (e.g. meters),
/// stereo camera-parallax properties (e.g. making sure objects at infinity are rendered
/// with the proper separation), measuring VR geometry sizes and distances and more.
@@ -1984,7 +2021,7 @@ typedef enum ovrDebugHudStereoMode_
} ovrDebugHudStereoMode;
-
+#if !defined(OVR_EXPORTING_CAPI)
// -----------------------------------------------------------------------------------
/// @name Property Access
@@ -2102,7 +2139,7 @@ OVR_PUBLIC_FUNCTION(ovrBool) ovr_SetString(ovrSession session, const char* prope
///@}
-
+#endif // !defined(OVR_EXPORTING_CAPI)
#ifdef __cplusplus
} // extern "C"
@@ -2163,10 +2200,10 @@ OVR_STATIC_ASSERT(sizeof(ovrLogLevel) == 4, "ovrLogLevel size mismatch");
OVR_STATIC_ASSERT(sizeof(ovrInitParams) == 4 + 4 + sizeof(ovrLogCallback) + sizeof(uintptr_t) + 4 + 4,
"ovrInitParams size mismatch");
-OVR_STATIC_ASSERT(sizeof(ovrHmdDesc) ==
+OVR_STATIC_ASSERT(sizeof(ovrHmdDesc) ==
+ sizeof(ovrHmdType) // Type
OVR_ON64(+ 4) // pad0
- + 64 // ProductName
+ + 64 // ProductName
+ 64 // Manufacturer
+ 2 // VendorId
+ 2 // ProductId
diff --git a/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_Audio.h b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_Audio.h
index 930dfcbe..dc61e19e 100644
--- a/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_Audio.h
+++ b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_Audio.h
@@ -17,6 +17,8 @@
#include "OVR_CAPI.h"
#define OVR_AUDIO_MAX_DEVICE_STR_SIZE 128
+#if !defined(OVR_EXPORTING_CAPI)
+
/// Gets the ID of the preferred VR audio output device.
///
/// \param[out] deviceOutId The ID of the user's preferred VR audio device to use, which will be valid upon a successful return value, else it will be WAVE_MAPPER.
@@ -75,6 +77,8 @@ OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceInGuidStr(WCHAR deviceInStrBuff
///
OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetAudioDeviceInGuid(GUID* deviceInGuid);
+#endif // !defined(OVR_EXPORTING_CAPI)
+
#endif //OVR_OS_MS
#endif // OVR_CAPI_Audio_h
diff --git a/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_D3D.h b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_D3D.h
index 982af8f0..374dab84 100644
--- a/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_D3D.h
+++ b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_D3D.h
@@ -14,6 +14,8 @@
#if defined (_WIN32)
#include <Unknwn.h>
+#if !defined(OVR_EXPORTING_CAPI)
+
//-----------------------------------------------------------------------------------
// ***** Direct3D Specific
@@ -149,6 +151,7 @@ OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetMirrorTextureBufferDX(ovrSession session,
IID iid,
void** out_Buffer);
+#endif // !defined(OVR_EXPORTING_CAPI)
#endif // _WIN32
diff --git a/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_GL.h b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_GL.h
index 81487947..1c073f46 100644
--- a/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_GL.h
+++ b/src/external/OculusSDK/LibOVR/Include/OVR_CAPI_GL.h
@@ -9,6 +9,8 @@
#include "OVR_CAPI.h"
+#if !defined(OVR_EXPORTING_CAPI)
+
/// Creates a TextureSwapChain suitable for use with OpenGL.
///
/// \param[in] session Specifies an ovrSession previously returned by ovr_Create.
@@ -95,5 +97,6 @@ OVR_PUBLIC_FUNCTION(ovrResult) ovr_GetMirrorTextureBufferGL(ovrSession session,
ovrMirrorTexture mirrorTexture,
unsigned int* out_TexId);
+#endif // !defined(OVR_EXPORTING_CAPI)
#endif // OVR_CAPI_GL_h
diff --git a/src/external/OculusSDK/LibOVR/Include/OVR_ErrorCode.h b/src/external/OculusSDK/LibOVR/Include/OVR_ErrorCode.h
index 9fc527c7..a8b810ea 100644
--- a/src/external/OculusSDK/LibOVR/Include/OVR_ErrorCode.h
+++ b/src/external/OculusSDK/LibOVR/Include/OVR_ErrorCode.h
@@ -88,6 +88,7 @@ typedef enum ovrErrorType_
ovrError_ClientSkippedDestroy = -1012, ///< The client failed to call ovr_Destroy on an active session before calling ovr_Shutdown. Or the client crashed.
ovrError_ClientSkippedShutdown = -1013, ///< The client failed to call ovr_Shutdown or the client crashed.
ovrError_ServiceDeadlockDetected = -1014, ///< The service watchdog discovered a deadlock.
+ ovrError_InvalidOperation = -1015, ///< Function call is invalid for object's current state
/* Audio error range, reserved for Audio errors. */
ovrError_AudioDeviceNotFound = -2001, ///< Failure to find the specified audio device.
@@ -115,6 +116,9 @@ typedef enum ovrErrorType_
ovrError_HybridGraphicsNotSupported = -3018, ///< The system is using hybrid graphics (Optimus, etc...), which is not support.
ovrError_DisplayManagerInit = -3019, ///< Initialization of the DisplayManager failed.
ovrError_TrackerDriverInit = -3020, ///< Failed to get the interface for an attached tracker
+ ovrError_LibSignCheck = -3021, ///< LibOVRRT signature check failure.
+ ovrError_LibPath = -3022, ///< LibOVRRT path failure.
+ ovrError_LibSymbols = -3023, ///< LibOVRRT symbol resolution failure.
/* Rendering errors */
ovrError_DisplayLost = -6000, ///< In the event of a system-wide graphics reset or cable unplug this is returned to the app.
@@ -130,6 +134,11 @@ typedef enum ovrErrorType_
/* Fatal errors */
ovrError_RuntimeException = -7000, ///< A runtime exception occurred. The application is required to shutdown LibOVR and re-initialize it before this error state will be cleared.
+ /* Calibration errors */
+ ovrError_NoCalibration = -9000, ///< Result of a missing calibration block
+ ovrError_OldVersion = -9001, ///< Result of an old calibration block
+ ovrError_MisformattedBlock = -9002, ///< Result of a bad calibration block due to lengths
+
} ovrErrorType;
diff --git a/src/external/OculusSDK/LibOVR/Include/OVR_Version.h b/src/external/OculusSDK/LibOVR/Include/OVR_Version.h
index d8378304..8d213df5 100644
--- a/src/external/OculusSDK/LibOVR/Include/OVR_Version.h
+++ b/src/external/OculusSDK/LibOVR/Include/OVR_Version.h
@@ -19,7 +19,7 @@
// Master version numbers
#define OVR_PRODUCT_VERSION 1 // Product version doesn't participate in semantic versioning.
#define OVR_MAJOR_VERSION 1 // If you change these values then you need to also make sure to change LibOVR/Projects/Windows/LibOVR.props in parallel.
-#define OVR_MINOR_VERSION 6 //
+#define OVR_MINOR_VERSION 7 //
#define OVR_PATCH_VERSION 0
#define OVR_BUILD_NUMBER 0
diff --git a/src/external/OculusSDK/LibOVR/LibOVRRT32_1.dll b/src/external/OculusSDK/LibOVR/LibOVRRT32_1.dll
index 843c0e44..7a42d443 100644
--- a/src/external/OculusSDK/LibOVR/LibOVRRT32_1.dll
+++ b/src/external/OculusSDK/LibOVR/LibOVRRT32_1.dll
Binary files differ
diff --git a/src/external/dr_flac.h b/src/external/dr_flac.h
new file mode 100644
index 00000000..d7b66f20
--- /dev/null
+++ b/src/external/dr_flac.h
@@ -0,0 +1,4395 @@
+// FLAC audio decoder. Public domain. See "unlicense" statement at the end of this file.
+// dr_flac - v0.4 - 2016-09-29
+//
+// David Reid - mackron@gmail.com
+
+// USAGE
+//
+// dr_flac is a single-file library. To use it, do something like the following in one .c file.
+// #define DR_FLAC_IMPLEMENTATION
+// #include "dr_flac.h"
+//
+// You can then #include this file in other parts of the program as you would with any other header file. To decode audio data,
+// do something like the following:
+//
+// drflac* pFlac = drflac_open_file("MySong.flac");
+// if (pFlac == NULL) {
+// // Failed to open FLAC file
+// }
+//
+// int32_t* pSamples = malloc(pFlac->totalSampleCount * sizeof(int32_t));
+// uint64_t numberOfInterleavedSamplesActuallyRead = drflac_read_s32(pFlac, pFlac->totalSampleCount, pSamples);
+//
+// The drflac object represents the decoder. It is a transparent type so all the information you need, such as the number of
+// channels and the bits per sample, should be directly accessible - just make sure you don't change their values. Samples are
+// always output as interleaved signed 32-bit PCM. In the example above a native FLAC stream was opened, however dr_flac has
+// seamless support for Ogg encapsulated FLAC streams as well.
+//
+// You do not need to decode the entire stream in one go - you just specify how many samples you'd like at any given time and
+// the decoder will give you as many samples as it can, up to the amount requested. Later on when you need the next batch of
+// samples, just call it again. Example:
+//
+// while (drflac_read_s32(pFlac, chunkSize, pChunkSamples) > 0) {
+// do_something();
+// }
+//
+// You can seek to a specific sample with drflac_seek_to_sample(). The given sample is based on interleaving. So for example,
+// if you were to seek to the sample at index 0 in a stereo stream, you'll be seeking to the first sample of the left channel.
+// The sample at index 1 will be the first sample of the right channel. The sample at index 2 will be the second sample of the
+// left channel, etc.
+//
+//
+// If you just want to quickly decode an entire FLAC file in one go you can do something like this:
+//
+// unsigned int channels;
+// unsigned int sampleRate;
+// uint64_t totalSampleCount;
+// int32_t* pSampleData = drflac_open_and_decode_file("MySong.flac", &channels, &sampleRate, &totalSampleCount);
+// if (pSampleData == NULL) {
+// // Failed to open and decode FLAC file.
+// }
+//
+// ...
+//
+// drflac_free(pSampleData);
+//
+//
+// If you need access to metadata (album art, etc.), use drflac_open_with_metadata(), drflac_open_file_with_metdata() or
+// drflac_open_memory_with_metadata(). The rationale for keeping these APIs separate is that they're slightly slower than the
+// normal versions and also just a little bit harder to use.
+//
+// dr_flac reports metadata to the application through the use of a callback, and every metadata block is reported before
+// drflac_open_with_metdata() returns. See https://github.com/mackron/dr_libs_tests/blob/master/dr_flac/dr_flac_test_2.c for
+// an example on how to read metadata.
+//
+//
+//
+// OPTIONS
+// #define these options before including this file.
+//
+// #define DR_FLAC_NO_STDIO
+// Disable drflac_open_file().
+//
+// #define DR_FLAC_NO_OGG
+// Disables support for Ogg/FLAC streams.
+//
+// #define DR_FLAC_NO_WIN32_IO
+// In the Win32 build, dr_flac uses the Win32 IO APIs for drflac_open_file() by default. This setting will make it use the
+// standard FILE APIs instead. Ignored when DR_FLAC_NO_STDIO is #defined. (The rationale for this configuration is that
+// there's a bug in one compiler's Win32 implementation of the FILE APIs which is not present in the Win32 IO APIs.)
+//
+// #define DR_FLAC_BUFFER_SIZE <number>
+// Defines the size of the internal buffer to store data from onRead(). This buffer is used to reduce the number of calls
+// back to the client for more data. Larger values means more memory, but better performance. My tests show diminishing
+// returns after about 4KB (which is the default). Consider reducing this if you have a very efficient implementation of
+// onRead(), or increase it if it's very inefficient. Must be a multiple of 8.
+//
+//
+//
+// QUICK NOTES
+// - Based on my tests, the performance of the 32-bit build is at about parity with the reference implementation. The 64-bit build
+// is slightly faster.
+// - dr_flac does not currently do any CRC checks.
+// - dr_flac should work fine with valid native FLAC files, but for broadcast streams it won't work if the header and STREAMINFO
+// block is unavailable.
+// - Audio data is output as signed 32-bit PCM, regardless of the bits per sample the FLAC stream is encoded as.
+// - This has not been tested on big-endian architectures.
+// - Rice codes in unencoded binary form (see https://xiph.org/flac/format.html#rice_partition) has not been tested. If anybody
+// knows where I can find some test files for this, let me know.
+// - Perverse and erroneous files have not been tested. Again, if you know where I can get some test files let me know.
+// - dr_flac is not thread-safe, but it's APIs can be called from any thread so long as you do your own synchronization.
+
+#ifndef dr_flac_h
+#define dr_flac_h
+
+#include <stdint.h>
+#include <stddef.h>
+
+#ifndef DR_BOOL_DEFINED
+#define DR_BOOL_DEFINED
+#ifdef _WIN32
+typedef char drBool8;
+typedef int drBool32;
+#else
+#include <stdint.h>
+typedef int8_t drBool8;
+typedef int32_t drBool32;
+#endif
+#define DR_TRUE 1
+#define DR_FALSE 0
+#endif
+
+// As data is read from the client it is placed into an internal buffer for fast access. This controls the
+// size of that buffer. Larger values means more speed, but also more memory. In my testing there is diminishing
+// returns after about 4KB, but you can fiddle with this to suit your own needs. Must be a multiple of 8.
+#ifndef DR_FLAC_BUFFER_SIZE
+#define DR_FLAC_BUFFER_SIZE 4096
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Check if we can enable 64-bit optimizations.
+#if defined(_WIN64)
+#define DRFLAC_64BIT
+#endif
+
+#if defined(__GNUC__)
+#if defined(__x86_64__) || defined(__ppc64__)
+#define DRFLAC_64BIT
+#endif
+#endif
+
+#ifdef DRFLAC_64BIT
+typedef uint64_t drflac_cache_t;
+#else
+typedef uint32_t drflac_cache_t;
+#endif
+
+// The various metadata block types.
+#define DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO 0
+#define DRFLAC_METADATA_BLOCK_TYPE_PADDING 1
+#define DRFLAC_METADATA_BLOCK_TYPE_APPLICATION 2
+#define DRFLAC_METADATA_BLOCK_TYPE_SEEKTABLE 3
+#define DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT 4
+#define DRFLAC_METADATA_BLOCK_TYPE_CUESHEET 5
+#define DRFLAC_METADATA_BLOCK_TYPE_PICTURE 6
+#define DRFLAC_METADATA_BLOCK_TYPE_INVALID 127
+
+// The various picture types specified in the PICTURE block.
+#define DRFLAC_PICTURE_TYPE_OTHER 0
+#define DRFLAC_PICTURE_TYPE_FILE_ICON 1
+#define DRFLAC_PICTURE_TYPE_OTHER_FILE_ICON 2
+#define DRFLAC_PICTURE_TYPE_COVER_FRONT 3
+#define DRFLAC_PICTURE_TYPE_COVER_BACK 4
+#define DRFLAC_PICTURE_TYPE_LEAFLET_PAGE 5
+#define DRFLAC_PICTURE_TYPE_MEDIA 6
+#define DRFLAC_PICTURE_TYPE_LEAD_ARTIST 7
+#define DRFLAC_PICTURE_TYPE_ARTIST 8
+#define DRFLAC_PICTURE_TYPE_CONDUCTOR 9
+#define DRFLAC_PICTURE_TYPE_BAND 10
+#define DRFLAC_PICTURE_TYPE_COMPOSER 11
+#define DRFLAC_PICTURE_TYPE_LYRICIST 12
+#define DRFLAC_PICTURE_TYPE_RECORDING_LOCATION 13
+#define DRFLAC_PICTURE_TYPE_DURING_RECORDING 14
+#define DRFLAC_PICTURE_TYPE_DURING_PERFORMANCE 15
+#define DRFLAC_PICTURE_TYPE_SCREEN_CAPTURE 16
+#define DRFLAC_PICTURE_TYPE_BRIGHT_COLORED_FISH 17
+#define DRFLAC_PICTURE_TYPE_ILLUSTRATION 18
+#define DRFLAC_PICTURE_TYPE_BAND_LOGOTYPE 19
+#define DRFLAC_PICTURE_TYPE_PUBLISHER_LOGOTYPE 20
+
+typedef enum
+{
+ drflac_container_native,
+ drflac_container_ogg
+} drflac_container;
+
+typedef enum
+{
+ drflac_seek_origin_start,
+ drflac_seek_origin_current
+} drflac_seek_origin;
+
+// Packing is important on this structure because we map this directly to the raw data within the SEEKTABLE metadata block.
+#pragma pack(2)
+typedef struct
+{
+ uint64_t firstSample;
+ uint64_t frameOffset; // The offset from the first byte of the header of the first frame.
+ uint16_t sampleCount;
+} drflac_seekpoint;
+#pragma pack()
+
+typedef struct
+{
+ uint16_t minBlockSize;
+ uint16_t maxBlockSize;
+ uint32_t minFrameSize;
+ uint32_t maxFrameSize;
+ uint32_t sampleRate;
+ uint8_t channels;
+ uint8_t bitsPerSample;
+ uint64_t totalSampleCount;
+ uint8_t md5[16];
+} drflac_streaminfo;
+
+typedef struct
+{
+ // The metadata type. Use this to know how to interpret the data below.
+ uint32_t type;
+
+ // A pointer to the raw data. This points to a temporary buffer so don't hold on to it. It's best to
+ // not modify the contents of this buffer. Use the structures below for more meaningful and structured
+ // information about the metadata. It's possible for this to be null.
+ const void* pRawData;
+
+ // The size in bytes of the block and the buffer pointed to by pRawData if it's non-NULL.
+ uint32_t rawDataSize;
+
+ union
+ {
+ drflac_streaminfo streaminfo;
+
+ struct
+ {
+ int unused;
+ } padding;
+
+ struct
+ {
+ uint32_t id;
+ const void* pData;
+ uint32_t dataSize;
+ } application;
+
+ struct
+ {
+ uint32_t seekpointCount;
+ const drflac_seekpoint* pSeekpoints;
+ } seektable;
+
+ struct
+ {
+ uint32_t vendorLength;
+ const char* vendor;
+ uint32_t commentCount;
+ const char* comments;
+ } vorbis_comment;
+
+ struct
+ {
+ char catalog[128];
+ uint64_t leadInSampleCount;
+ drBool32 isCD;
+ uint8_t trackCount;
+ const uint8_t* pTrackData;
+ } cuesheet;
+
+ struct
+ {
+ uint32_t type;
+ uint32_t mimeLength;
+ const char* mime;
+ uint32_t descriptionLength;
+ const char* description;
+ uint32_t width;
+ uint32_t height;
+ uint32_t colorDepth;
+ uint32_t indexColorCount;
+ uint32_t pictureDataSize;
+ const uint8_t* pPictureData;
+ } picture;
+ } data;
+
+} drflac_metadata;
+
+
+// Callback for when data needs to be read from the client.
+//
+// pUserData [in] The user data that was passed to drflac_open() and family.
+// pBufferOut [out] The output buffer.
+// bytesToRead [in] The number of bytes to read.
+//
+// Returns the number of bytes actually read.
+typedef size_t (* drflac_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead);
+
+// Callback for when data needs to be seeked.
+//
+// pUserData [in] The user data that was passed to drflac_open() and family.
+// offset [in] The number of bytes to move, relative to the origin. Will never be negative.
+// origin [in] The origin of the seek - the current position or the start of the stream.
+//
+// Returns whether or not the seek was successful.
+//
+// The offset will never be negative. Whether or not it is relative to the beginning or current position is determined
+// by the "origin" parameter which will be either drflac_seek_origin_start or drflac_seek_origin_current.
+typedef drBool32 (* drflac_seek_proc)(void* pUserData, int offset, drflac_seek_origin origin);
+
+// Callback for when a metadata block is read.
+//
+// pUserData [in] The user data that was passed to drflac_open() and family.
+// pMetadata [in] A pointer to a structure containing the data of the metadata block.
+//
+// Use pMetadata->type to determine which metadata block is being handled and how to read the data.
+typedef void (* drflac_meta_proc)(void* pUserData, drflac_metadata* pMetadata);
+
+
+// Structure for internal use. Only used for decoders opened with drflac_open_memory.
+typedef struct
+{
+ const uint8_t* data;
+ size_t dataSize;
+ size_t currentReadPos;
+} drflac__memory_stream;
+
+// Structure for internal use. Used for bit streaming.
+typedef struct
+{
+ // The function to call when more data needs to be read.
+ drflac_read_proc onRead;
+
+ // The function to call when the current read position needs to be moved.
+ drflac_seek_proc onSeek;
+
+ // The user data to pass around to onRead and onSeek.
+ void* pUserData;
+
+
+ // The number of unaligned bytes in the L2 cache. This will always be 0 until the end of the stream is hit. At the end of the
+ // stream there will be a number of bytes that don't cleanly fit in an L1 cache line, so we use this variable to know whether
+ // or not the bistreamer needs to run on a slower path to read those last bytes. This will never be more than sizeof(drflac_cache_t).
+ size_t unalignedByteCount;
+
+ // The content of the unaligned bytes.
+ drflac_cache_t unalignedCache;
+
+ // The index of the next valid cache line in the "L2" cache.
+ size_t nextL2Line;
+
+ // The number of bits that have been consumed by the cache. This is used to determine how many valid bits are remaining.
+ size_t consumedBits;
+
+ // The cached data which was most recently read from the client. There are two levels of cache. Data flows as such:
+ // Client -> L2 -> L1. The L2 -> L1 movement is aligned and runs on a fast path in just a few instructions.
+ drflac_cache_t cacheL2[DR_FLAC_BUFFER_SIZE/sizeof(drflac_cache_t)];
+ drflac_cache_t cache;
+
+} drflac_bs;
+
+typedef struct
+{
+ // The type of the subframe: SUBFRAME_CONSTANT, SUBFRAME_VERBATIM, SUBFRAME_FIXED or SUBFRAME_LPC.
+ uint8_t subframeType;
+
+ // The number of wasted bits per sample as specified by the sub-frame header.
+ uint8_t wastedBitsPerSample;
+
+ // The order to use for the prediction stage for SUBFRAME_FIXED and SUBFRAME_LPC.
+ uint8_t lpcOrder;
+
+ // The number of bits per sample for this subframe. This is not always equal to the current frame's bit per sample because
+ // an extra bit is required for side channels when interchannel decorrelation is being used.
+ uint32_t bitsPerSample;
+
+ // A pointer to the buffer containing the decoded samples in the subframe. This pointer is an offset from drflac::pExtraData, or
+ // NULL if the heap is not being used. Note that it's a signed 32-bit integer for each value.
+ int32_t* pDecodedSamples;
+
+} drflac_subframe;
+
+typedef struct
+{
+ // If the stream uses variable block sizes, this will be set to the index of the first sample. If fixed block sizes are used, this will
+ // always be set to 0.
+ uint64_t sampleNumber;
+
+ // If the stream uses fixed block sizes, this will be set to the frame number. If variable block sizes are used, this will always be 0.
+ uint32_t frameNumber;
+
+ // The sample rate of this frame.
+ uint32_t sampleRate;
+
+ // The number of samples in each sub-frame within this frame.
+ uint16_t blockSize;
+
+ // The channel assignment of this frame. This is not always set to the channel count. If interchannel decorrelation is being used this
+ // will be set to DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE, DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE or DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE.
+ uint8_t channelAssignment;
+
+ // The number of bits per sample within this frame.
+ uint8_t bitsPerSample;
+
+ // The frame's CRC. This is set, but unused at the moment.
+ uint8_t crc8;
+
+} drflac_frame_header;
+
+typedef struct
+{
+ // The header.
+ drflac_frame_header header;
+
+ // The number of samples left to be read in this frame. This is initially set to the block size multiplied by the channel count. As samples
+ // are read, this will be decremented. When it reaches 0, the decoder will see this frame as fully consumed and load the next frame.
+ uint32_t samplesRemaining;
+
+ // The list of sub-frames within the frame. There is one sub-frame for each channel, and there's a maximum of 8 channels.
+ drflac_subframe subframes[8];
+
+} drflac_frame;
+
+typedef struct
+{
+ // The function to call when a metadata block is read.
+ drflac_meta_proc onMeta;
+
+ // The user data posted to the metadata callback function.
+ void* pUserDataMD;
+
+
+ // The sample rate. Will be set to something like 44100.
+ uint32_t sampleRate;
+
+ // The number of channels. This will be set to 1 for monaural streams, 2 for stereo, etc. Maximum 8. This is set based on the
+ // value specified in the STREAMINFO block.
+ uint8_t channels;
+
+ // The bits per sample. Will be set to somthing like 16, 24, etc.
+ uint8_t bitsPerSample;
+
+ // The maximum block size, in samples. This number represents the number of samples in each channel (not combined).
+ uint16_t maxBlockSize;
+
+ // The total number of samples making up the stream. This includes every channel. For example, if the stream has 2 channels,
+ // with each channel having a total of 4096, this value will be set to 2*4096 = 8192. Can be 0 in which case it's still a
+ // valid stream, but just means the total sample count is unknown. Likely the case with streams like internet radio.
+ uint64_t totalSampleCount;
+
+
+ // The container type. This is set based on whether or not the decoder was opened from a native or Ogg stream.
+ drflac_container container;
+
+
+ // The position of the seektable in the file.
+ uint64_t seektablePos;
+
+ // The size of the seektable.
+ uint32_t seektableSize;
+
+
+ // Information about the frame the decoder is currently sitting on.
+ drflac_frame currentFrame;
+
+ // The position of the first frame in the stream. This is only ever used for seeking.
+ uint64_t firstFramePos;
+
+
+ // A hack to avoid a malloc() when opening a decoder with drflac_open_memory().
+ drflac__memory_stream memoryStream;
+
+
+
+ // A pointer to the decoded sample data. This is an offset of pExtraData.
+ int32_t* pDecodedSamples;
+
+
+ // The bit streamer. The raw FLAC data is fed through this object.
+ drflac_bs bs;
+
+ // Variable length extra data. We attach this to the end of the object so we avoid unnecessary mallocs.
+ uint8_t pExtraData[1];
+
+} drflac;
+
+
+// Opens a FLAC decoder.
+//
+// onRead [in] The function to call when data needs to be read from the client.
+// onSeek [in] The function to call when the read position of the client data needs to move.
+// pUserData [in, optional] A pointer to application defined data that will be passed to onRead and onSeek.
+//
+// Returns a pointer to an object representing the decoder.
+//
+// Close the decoder with drflac_close().
+//
+// This function will automatically detect whether or not you are attempting to open a native or Ogg encapsulated
+// FLAC, both of which should work seamlessly without any manual intervention. Ogg encapsulation also works with
+// multiplexed streams which basically means it can play FLAC encoded audio tracks in videos.
+//
+// This is the lowest level function for opening a FLAC stream. You can also use drflac_open_file() and drflac_open_memory()
+// to open the stream from a file or from a block of memory respectively.
+//
+// The STREAMINFO block must be present for this to succeed.
+//
+// See also: drflac_open_file(), drflac_open_memory(), drflac_open_with_metadata(), drflac_close()
+drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData);
+
+// Opens a FLAC decoder and notifies the caller of the metadata chunks (album art, etc.).
+//
+// onRead [in] The function to call when data needs to be read from the client.
+// onSeek [in] The function to call when the read position of the client data needs to move.
+// onMeta [in] The function to call for every metadata block.
+// pUserData [in, optional] A pointer to application defined data that will be passed to onRead, onSeek and onMeta.
+//
+// Returns a pointer to an object representing the decoder.
+//
+// Close the decoder with drflac_close().
+//
+// This is slower than drflac_open(), so avoid this one if you don't need metadata. Internally, this will do a malloc()
+// and free() for every metadata block except for STREAMINFO and PADDING blocks.
+//
+// The caller is notified of the metadata via the onMeta callback. All metadata blocks with be handled before the function
+// returns.
+//
+// See also: drflac_open_file_with_metadata(), drflac_open_memory_with_metadata(), drflac_open(), drflac_close()
+drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData);
+
+// Closes the given FLAC decoder.
+//
+// pFlac [in] The decoder to close.
+//
+// This will destroy the decoder object.
+void drflac_close(drflac* pFlac);
+
+
+// Reads sample data from the given FLAC decoder, output as interleaved signed 32-bit PCM.
+//
+// pFlac [in] The decoder.
+// samplesToRead [in] The number of samples to read.
+// pBufferOut [out, optional] A pointer to the buffer that will receive the decoded samples.
+//
+// Returns the number of samples actually read.
+//
+// pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of samples
+// seeked.
+uint64_t drflac_read_s32(drflac* pFlac, uint64_t samplesToRead, int32_t* pBufferOut);
+
+// Seeks to the sample at the given index.
+//
+// pFlac [in] The decoder.
+// sampleIndex [in] The index of the sample to seek to. See notes below.
+//
+// Returns DR_TRUE if successful; DR_FALSE otherwise.
+//
+// The sample index is based on interleaving. In a stereo stream, for example, the sample at index 0 is the first sample
+// in the left channel; the sample at index 1 is the first sample on the right channel, and so on.
+//
+// When seeking, you will likely want to ensure it's rounded to a multiple of the channel count. You can do this with
+// something like drflac_seek_to_sample(pFlac, (mySampleIndex + (mySampleIndex % pFlac->channels)))
+drBool32 drflac_seek_to_sample(drflac* pFlac, uint64_t sampleIndex);
+
+
+
+#ifndef DR_FLAC_NO_STDIO
+// Opens a FLAC decoder from the file at the given path.
+//
+// filename [in] The path of the file to open, either absolute or relative to the current directory.
+//
+// Returns a pointer to an object representing the decoder.
+//
+// Close the decoder with drflac_close().
+//
+// This will hold a handle to the file until the decoder is closed with drflac_close(). Some platforms will restrict the
+// number of files a process can have open at any given time, so keep this mind if you have many decoders open at the
+// same time.
+//
+// See also: drflac_open(), drflac_open_file_with_metadata(), drflac_close()
+drflac* drflac_open_file(const char* filename);
+
+// Opens a FLAC decoder from the file at the given path and notifies the caller of the metadata chunks (album art, etc.)
+//
+// Look at the documentation for drflac_open_with_metadata() for more information on how metadata is handled.
+drflac* drflac_open_file_with_metadata(const char* filename, drflac_meta_proc onMeta, void* pUserData);
+#endif
+
+// Opens a FLAC decoder from a pre-allocated block of memory
+//
+// This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for
+// the lifetime of the decoder.
+drflac* drflac_open_memory(const void* data, size_t dataSize);
+
+// Opens a FLAC decoder from a pre-allocated block of memory and notifies the caller of the metadata chunks (album art, etc.)
+//
+// Look at the documentation for drflac_open_with_metadata() for more information on how metadata is handled.
+drflac* drflac_open_memory_with_metadata(const void* data, size_t dataSize, drflac_meta_proc onMeta, void* pUserData);
+
+
+
+//// High Level APIs ////
+
+// Opens a FLAC stream from the given callbacks and fully decodes it in a single operation. The return value is a
+// pointer to the sample data as interleaved signed 32-bit PCM. The returned data must be freed with drflac_free().
+//
+// Sometimes a FLAC file won't keep track of the total sample count. In this situation the function will continuously
+// read samples into a dynamically sized buffer on the heap until no samples are left.
+//
+// Do not call this function on a broadcast type of stream (like internet radio streams and whatnot).
+int32_t* drflac_open_and_decode_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount);
+
+#ifndef DR_FLAC_NO_STDIO
+// Same as drflac_open_and_decode_s32() except opens the decoder from a file.
+int32_t* drflac_open_and_decode_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount);
+#endif
+
+// Same as drflac_open_and_decode_s32() except opens the decoder from a block of memory.
+int32_t* drflac_open_and_decode_memory_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount);
+
+// Frees data returned by drflac_open_and_decode_*().
+void drflac_free(void* pSampleDataReturnedByOpenAndDecode);
+
+
+// Structure representing an iterator for vorbis comments in a VORBIS_COMMENT metadata block.
+typedef struct
+{
+ uint32_t countRemaining;
+ const char* pRunningData;
+} drflac_vorbis_comment_iterator;
+
+// Initializes a vorbis comment iterator. This can be used for iterating over the vorbis comments in a VORBIS_COMMENT
+// metadata block.
+void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, uint32_t commentCount, const char* pComments);
+
+// Goes to the next vorbis comment in the given iterator. If null is returned it means there are no more comments. The
+// returned string is NOT null terminated.
+const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, uint32_t* pCommentLengthOut);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif //dr_flac_h
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// IMPLEMENTATION
+//
+///////////////////////////////////////////////////////////////////////////////
+#ifdef DR_FLAC_IMPLEMENTATION
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#ifdef _MSC_VER
+#include <intrin.h> // For _byteswap_ulong and _byteswap_uint64
+#endif
+
+#ifdef __linux__
+#define _BSD_SOURCE
+#include <endian.h>
+#endif
+
+#ifdef _MSC_VER
+#define DRFLAC_INLINE __forceinline
+#else
+#define DRFLAC_INLINE inline
+#endif
+
+#define DRFLAC_SUBFRAME_CONSTANT 0
+#define DRFLAC_SUBFRAME_VERBATIM 1
+#define DRFLAC_SUBFRAME_FIXED 8
+#define DRFLAC_SUBFRAME_LPC 32
+#define DRFLAC_SUBFRAME_RESERVED 255
+
+#define DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE 0
+#define DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2 1
+
+#define DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT 0
+#define DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE 8
+#define DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE 9
+#define DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE 10
+
+
+//// Endian Management ////
+static DRFLAC_INLINE drBool32 drflac__is_little_endian()
+{
+ int n = 1;
+ return (*(char*)&n) == 1;
+}
+
+static DRFLAC_INLINE uint16_t drflac__swap_endian_uint16(uint16_t n)
+{
+#ifdef _MSC_VER
+ return _byteswap_ushort(n);
+#elif defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
+ return __builtin_bswap16(n);
+#else
+ return ((n & 0xFF00) >> 8) |
+ ((n & 0x00FF) << 8);
+#endif
+}
+
+static DRFLAC_INLINE uint32_t drflac__swap_endian_uint32(uint32_t n)
+{
+#ifdef _MSC_VER
+ return _byteswap_ulong(n);
+#elif defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
+ return __builtin_bswap32(n);
+#else
+ return ((n & 0xFF000000) >> 24) |
+ ((n & 0x00FF0000) >> 8) |
+ ((n & 0x0000FF00) << 8) |
+ ((n & 0x000000FF) << 24);
+#endif
+}
+
+static DRFLAC_INLINE uint64_t drflac__swap_endian_uint64(uint64_t n)
+{
+#ifdef _MSC_VER
+ return _byteswap_uint64(n);
+#elif defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
+ return __builtin_bswap64(n);
+#else
+ return ((n & 0xFF00000000000000ULL) >> 56) |
+ ((n & 0x00FF000000000000ULL) >> 40) |
+ ((n & 0x0000FF0000000000ULL) >> 24) |
+ ((n & 0x000000FF00000000ULL) >> 8) |
+ ((n & 0x00000000FF000000ULL) << 8) |
+ ((n & 0x0000000000FF0000ULL) << 24) |
+ ((n & 0x000000000000FF00ULL) << 40) |
+ ((n & 0x00000000000000FFULL) << 56);
+#endif
+}
+
+static DRFLAC_INLINE uint16_t drflac__be2host_16(uint16_t n)
+{
+#ifdef __linux__
+ return be16toh(n);
+#else
+ if (drflac__is_little_endian()) {
+ return drflac__swap_endian_uint16(n);
+ }
+
+ return n;
+#endif
+}
+
+static DRFLAC_INLINE uint32_t drflac__be2host_32(uint32_t n)
+{
+#ifdef __linux__
+ return be32toh(n);
+#else
+ if (drflac__is_little_endian()) {
+ return drflac__swap_endian_uint32(n);
+ }
+
+ return n;
+#endif
+}
+
+static DRFLAC_INLINE uint64_t drflac__be2host_64(uint64_t n)
+{
+#ifdef __linux__
+ return be64toh(n);
+#else
+ if (drflac__is_little_endian()) {
+ return drflac__swap_endian_uint64(n);
+ }
+
+ return n;
+#endif
+}
+
+
+static DRFLAC_INLINE uint32_t drflac__le2host_32(uint32_t n)
+{
+#ifdef __linux__
+ return le32toh(n);
+#else
+ if (!drflac__is_little_endian()) {
+ return drflac__swap_endian_uint32(n);
+ }
+
+ return n;
+#endif
+}
+
+
+#ifdef DRFLAC_64BIT
+#define drflac__be2host__cache_line drflac__be2host_64
+#else
+#define drflac__be2host__cache_line drflac__be2host_32
+#endif
+
+
+// BIT READING ATTEMPT #2
+//
+// This uses a 32- or 64-bit bit-shifted cache - as bits are read, the cache is shifted such that the first valid bit is sitting
+// on the most significant bit. It uses the notion of an L1 and L2 cache (borrowed from CPU architecture), where the L1 cache
+// is a 32- or 64-bit unsigned integer (depending on whether or not a 32- or 64-bit build is being compiled) and the L2 is an
+// array of "cache lines", with each cache line being the same size as the L1. The L2 is a buffer of about 4KB and is where data
+// from onRead() is read into.
+#define DRFLAC_CACHE_L1_SIZE_BYTES(bs) (sizeof((bs)->cache))
+#define DRFLAC_CACHE_L1_SIZE_BITS(bs) (sizeof((bs)->cache)*8)
+#define DRFLAC_CACHE_L1_BITS_REMAINING(bs) (DRFLAC_CACHE_L1_SIZE_BITS(bs) - ((bs)->consumedBits))
+#ifdef DRFLAC_64BIT
+#define DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount) (~(((uint64_t)-1LL) >> (_bitCount)))
+#else
+#define DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount) (~(((uint32_t)-1) >> (_bitCount)))
+#endif
+#define DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, _bitCount) (DRFLAC_CACHE_L1_SIZE_BITS(bs) - (_bitCount))
+#define DRFLAC_CACHE_L1_SELECT(bs, _bitCount) (((bs)->cache) & DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount))
+#define DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, _bitCount) (DRFLAC_CACHE_L1_SELECT((bs), _bitCount) >> DRFLAC_CACHE_L1_SELECTION_SHIFT((bs), _bitCount))
+#define DRFLAC_CACHE_L2_SIZE_BYTES(bs) (sizeof((bs)->cacheL2))
+#define DRFLAC_CACHE_L2_LINE_COUNT(bs) (DRFLAC_CACHE_L2_SIZE_BYTES(bs) / sizeof((bs)->cacheL2[0]))
+#define DRFLAC_CACHE_L2_LINES_REMAINING(bs) (DRFLAC_CACHE_L2_LINE_COUNT(bs) - (bs)->nextL2Line)
+
+static DRFLAC_INLINE drBool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs)
+{
+ // Fast path. Try loading straight from L2.
+ if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
+ bs->cache = bs->cacheL2[bs->nextL2Line++];
+ return DR_TRUE;
+ }
+
+ // If we get here it means we've run out of data in the L2 cache. We'll need to fetch more from the client, if there's
+ // any left.
+ if (bs->unalignedByteCount > 0) {
+ return DR_FALSE; // If we have any unaligned bytes it means there's not more aligned bytes left in the client.
+ }
+
+ size_t bytesRead = bs->onRead(bs->pUserData, bs->cacheL2, DRFLAC_CACHE_L2_SIZE_BYTES(bs));
+
+ bs->nextL2Line = 0;
+ if (bytesRead == DRFLAC_CACHE_L2_SIZE_BYTES(bs)) {
+ bs->cache = bs->cacheL2[bs->nextL2Line++];
+ return DR_TRUE;
+ }
+
+
+ // If we get here it means we were unable to retrieve enough data to fill the entire L2 cache. It probably
+ // means we've just reached the end of the file. We need to move the valid data down to the end of the buffer
+ // and adjust the index of the next line accordingly. Also keep in mind that the L2 cache must be aligned to
+ // the size of the L1 so we'll need to seek backwards by any misaligned bytes.
+ size_t alignedL1LineCount = bytesRead / DRFLAC_CACHE_L1_SIZE_BYTES(bs);
+
+ // We need to keep track of any unaligned bytes for later use.
+ bs->unalignedByteCount = bytesRead - (alignedL1LineCount * DRFLAC_CACHE_L1_SIZE_BYTES(bs));
+ if (bs->unalignedByteCount > 0) {
+ bs->unalignedCache = bs->cacheL2[alignedL1LineCount];
+ }
+
+ if (alignedL1LineCount > 0)
+ {
+ size_t offset = DRFLAC_CACHE_L2_LINE_COUNT(bs) - alignedL1LineCount;
+ for (size_t i = alignedL1LineCount; i > 0; --i) {
+ bs->cacheL2[i-1 + offset] = bs->cacheL2[i-1];
+ }
+
+ bs->nextL2Line = offset;
+ bs->cache = bs->cacheL2[bs->nextL2Line++];
+ return DR_TRUE;
+ }
+ else
+ {
+ // If we get into this branch it means we weren't able to load any L1-aligned data.
+ bs->nextL2Line = DRFLAC_CACHE_L2_LINE_COUNT(bs);
+ return DR_FALSE;
+ }
+}
+
+static drBool32 drflac__reload_cache(drflac_bs* bs)
+{
+ // Fast path. Try just moving the next value in the L2 cache to the L1 cache.
+ if (drflac__reload_l1_cache_from_l2(bs)) {
+ bs->cache = drflac__be2host__cache_line(bs->cache);
+ bs->consumedBits = 0;
+ return DR_TRUE;
+ }
+
+ // Slow path.
+
+ // If we get here it means we have failed to load the L1 cache from the L2. Likely we've just reached the end of the stream and the last
+ // few bytes did not meet the alignment requirements for the L2 cache. In this case we need to fall back to a slower path and read the
+ // data from the unaligned cache.
+ size_t bytesRead = bs->unalignedByteCount;
+ if (bytesRead == 0) {
+ return DR_FALSE;
+ }
+
+ assert(bytesRead < DRFLAC_CACHE_L1_SIZE_BYTES(bs));
+ bs->consumedBits = (DRFLAC_CACHE_L1_SIZE_BYTES(bs) - bytesRead) * 8;
+
+ bs->cache = drflac__be2host__cache_line(bs->unalignedCache);
+ bs->cache &= DRFLAC_CACHE_L1_SELECTION_MASK(DRFLAC_CACHE_L1_SIZE_BITS(bs) - bs->consumedBits); // <-- Make sure the consumed bits are always set to zero. Other parts of the library depend on this property.
+ return DR_TRUE;
+}
+
+static void drflac__reset_cache(drflac_bs* bs)
+{
+ bs->nextL2Line = DRFLAC_CACHE_L2_LINE_COUNT(bs); // <-- This clears the L2 cache.
+ bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs); // <-- This clears the L1 cache.
+ bs->cache = 0;
+ bs->unalignedByteCount = 0; // <-- This clears the trailing unaligned bytes.
+ bs->unalignedCache = 0;
+}
+
+static drBool32 drflac__seek_bits(drflac_bs* bs, size_t bitsToSeek)
+{
+ if (bitsToSeek <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
+ bs->consumedBits += bitsToSeek;
+ bs->cache <<= bitsToSeek;
+ return DR_TRUE;
+ } else {
+ // It straddles the cached data. This function isn't called too frequently so I'm favouring simplicity here.
+ bitsToSeek -= DRFLAC_CACHE_L1_BITS_REMAINING(bs);
+ bs->consumedBits += DRFLAC_CACHE_L1_BITS_REMAINING(bs);
+ bs->cache = 0;
+
+ size_t wholeBytesRemaining = bitsToSeek/8;
+ if (wholeBytesRemaining > 0)
+ {
+ // The next bytes to seek will be located in the L2 cache. The problem is that the L2 cache is not byte aligned,
+ // but rather DRFLAC_CACHE_L1_SIZE_BYTES aligned (usually 4 or 8). If, for example, the number of bytes to seek is
+ // 3, we'll need to handle it in a special way.
+ size_t wholeCacheLinesRemaining = wholeBytesRemaining / DRFLAC_CACHE_L1_SIZE_BYTES(bs);
+ if (wholeCacheLinesRemaining < DRFLAC_CACHE_L2_LINES_REMAINING(bs))
+ {
+ wholeBytesRemaining -= wholeCacheLinesRemaining * DRFLAC_CACHE_L1_SIZE_BYTES(bs);
+ bitsToSeek -= wholeCacheLinesRemaining * DRFLAC_CACHE_L1_SIZE_BITS(bs);
+ bs->nextL2Line += wholeCacheLinesRemaining;
+ }
+ else
+ {
+ wholeBytesRemaining -= DRFLAC_CACHE_L2_LINES_REMAINING(bs) * DRFLAC_CACHE_L1_SIZE_BYTES(bs);
+ bitsToSeek -= DRFLAC_CACHE_L2_LINES_REMAINING(bs) * DRFLAC_CACHE_L1_SIZE_BITS(bs);
+ bs->nextL2Line += DRFLAC_CACHE_L2_LINES_REMAINING(bs);
+
+ if (wholeBytesRemaining > 0) {
+ bs->onSeek(bs->pUserData, (int)wholeBytesRemaining, drflac_seek_origin_current);
+ bitsToSeek -= wholeBytesRemaining*8;
+ }
+ }
+ }
+
+
+ if (bitsToSeek > 0) {
+ if (!drflac__reload_cache(bs)) {
+ return DR_FALSE;
+ }
+
+ return drflac__seek_bits(bs, bitsToSeek);
+ }
+
+ return DR_TRUE;
+ }
+}
+
+static drBool32 drflac__read_uint32(drflac_bs* bs, unsigned int bitCount, uint32_t* pResultOut)
+{
+ assert(bs != NULL);
+ assert(pResultOut != NULL);
+ assert(bitCount > 0);
+ assert(bitCount <= 32);
+
+ if (bs->consumedBits == DRFLAC_CACHE_L1_SIZE_BITS(bs)) {
+ if (!drflac__reload_cache(bs)) {
+ return DR_FALSE;
+ }
+ }
+
+ if (bitCount <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
+ if (bitCount < DRFLAC_CACHE_L1_SIZE_BITS(bs)) {
+ *pResultOut = DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCount);
+ bs->consumedBits += bitCount;
+ bs->cache <<= bitCount;
+ } else {
+ *pResultOut = (uint32_t)bs->cache;
+ bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs);
+ bs->cache = 0;
+ }
+ return DR_TRUE;
+ } else {
+ // It straddles the cached data. It will never cover more than the next chunk. We just read the number in two parts and combine them.
+ size_t bitCountHi = DRFLAC_CACHE_L1_BITS_REMAINING(bs);
+ size_t bitCountLo = bitCount - bitCountHi;
+ uint32_t resultHi = DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountHi);
+
+ if (!drflac__reload_cache(bs)) {
+ return DR_FALSE;
+ }
+
+ *pResultOut = (resultHi << bitCountLo) | DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountLo);
+ bs->consumedBits += bitCountLo;
+ bs->cache <<= bitCountLo;
+ return DR_TRUE;
+ }
+}
+
+static drBool32 drflac__read_int32(drflac_bs* bs, unsigned int bitCount, int32_t* pResult)
+{
+ assert(bs != NULL);
+ assert(pResult != NULL);
+ assert(bitCount > 0);
+ assert(bitCount <= 32);
+
+ uint32_t result;
+ if (!drflac__read_uint32(bs, bitCount, &result)) {
+ return DR_FALSE;
+ }
+
+ uint32_t signbit = ((result >> (bitCount-1)) & 0x01);
+ result |= (~signbit + 1) << bitCount;
+
+ *pResult = (int32_t)result;
+ return DR_TRUE;
+}
+
+static drBool32 drflac__read_uint64(drflac_bs* bs, unsigned int bitCount, uint64_t* pResultOut)
+{
+ assert(bitCount <= 64);
+ assert(bitCount > 32);
+
+ uint32_t resultHi;
+ if (!drflac__read_uint32(bs, bitCount - 32, &resultHi)) {
+ return DR_FALSE;
+ }
+
+ uint32_t resultLo;
+ if (!drflac__read_uint32(bs, 32, &resultLo)) {
+ return DR_FALSE;
+ }
+
+ *pResultOut = (((uint64_t)resultHi) << 32) | ((uint64_t)resultLo);
+ return DR_TRUE;
+}
+
+// Function below is unused, but leaving it here in case I need to quickly add it again.
+#if 0
+static drBool32 drflac__read_int64(drflac_bs* bs, unsigned int bitCount, int64_t* pResultOut)
+{
+ assert(bitCount <= 64);
+
+ uint64_t result;
+ if (!drflac__read_uint64(bs, bitCount, &result)) {
+ return DR_FALSE;
+ }
+
+ uint64_t signbit = ((result >> (bitCount-1)) & 0x01);
+ result |= (~signbit + 1) << bitCount;
+
+ *pResultOut = (int64_t)result;
+ return DR_TRUE;
+}
+#endif
+
+static drBool32 drflac__read_uint16(drflac_bs* bs, unsigned int bitCount, uint16_t* pResult)
+{
+ assert(bs != NULL);
+ assert(pResult != NULL);
+ assert(bitCount > 0);
+ assert(bitCount <= 16);
+
+ uint32_t result;
+ if (!drflac__read_uint32(bs, bitCount, &result)) {
+ return DR_FALSE;
+ }
+
+ *pResult = (uint16_t)result;
+ return DR_TRUE;
+}
+
+static drBool32 drflac__read_int16(drflac_bs* bs, unsigned int bitCount, int16_t* pResult)
+{
+ assert(bs != NULL);
+ assert(pResult != NULL);
+ assert(bitCount > 0);
+ assert(bitCount <= 16);
+
+ int32_t result;
+ if (!drflac__read_int32(bs, bitCount, &result)) {
+ return DR_FALSE;
+ }
+
+ *pResult = (int16_t)result;
+ return DR_TRUE;
+}
+
+static drBool32 drflac__read_uint8(drflac_bs* bs, unsigned int bitCount, uint8_t* pResult)
+{
+ assert(bs != NULL);
+ assert(pResult != NULL);
+ assert(bitCount > 0);
+ assert(bitCount <= 8);
+
+ uint32_t result;
+ if (!drflac__read_uint32(bs, bitCount, &result)) {
+ return DR_FALSE;
+ }
+
+ *pResult = (uint8_t)result;
+ return DR_TRUE;
+}
+
+static drBool32 drflac__read_int8(drflac_bs* bs, unsigned int bitCount, int8_t* pResult)
+{
+ assert(bs != NULL);
+ assert(pResult != NULL);
+ assert(bitCount > 0);
+ assert(bitCount <= 8);
+
+ int32_t result;
+ if (!drflac__read_int32(bs, bitCount, &result)) {
+ return DR_FALSE;
+ }
+
+ *pResult = (int8_t)result;
+ return DR_TRUE;
+}
+
+
+static inline drBool32 drflac__seek_past_next_set_bit(drflac_bs* bs, unsigned int* pOffsetOut)
+{
+ unsigned int zeroCounter = 0;
+ while (bs->cache == 0) {
+ zeroCounter += (unsigned int)DRFLAC_CACHE_L1_BITS_REMAINING(bs);
+ if (!drflac__reload_cache(bs)) {
+ return DR_FALSE;
+ }
+ }
+
+ // At this point the cache should not be zero, in which case we know the first set bit should be somewhere in here. There is
+ // no need for us to perform any cache reloading logic here which should make things much faster.
+ assert(bs->cache != 0);
+
+ unsigned int bitOffsetTable[] = {
+ 0,
+ 4,
+ 3, 3,
+ 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1
+ };
+
+ unsigned int setBitOffsetPlus1 = bitOffsetTable[DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, 4)];
+ if (setBitOffsetPlus1 == 0) {
+ if (bs->cache == 1) {
+ setBitOffsetPlus1 = DRFLAC_CACHE_L1_SIZE_BITS(bs);
+ } else {
+ setBitOffsetPlus1 = 5;
+ for (;;)
+ {
+ if ((bs->cache & DRFLAC_CACHE_L1_SELECT(bs, setBitOffsetPlus1))) {
+ break;
+ }
+
+ setBitOffsetPlus1 += 1;
+ }
+ }
+ }
+
+ bs->consumedBits += setBitOffsetPlus1;
+ bs->cache <<= setBitOffsetPlus1;
+
+ *pOffsetOut = zeroCounter + setBitOffsetPlus1 - 1;
+ return DR_TRUE;
+}
+
+
+
+static drBool32 drflac__seek_to_byte(drflac_bs* bs, uint64_t offsetFromStart)
+{
+ assert(bs != NULL);
+ assert(offsetFromStart > 0);
+
+ // Seeking from the start is not quite as trivial as it sounds because the onSeek callback takes a signed 32-bit integer (which
+ // is intentional because it simplifies the implementation of the onSeek callbacks), however offsetFromStart is unsigned 64-bit.
+ // To resolve we just need to do an initial seek from the start, and then a series of offset seeks to make up the remainder.
+ if (offsetFromStart > 0x7FFFFFFF)
+ {
+ uint64_t bytesRemaining = offsetFromStart;
+ if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) {
+ return DR_FALSE;
+ }
+ bytesRemaining -= 0x7FFFFFFF;
+
+
+ while (bytesRemaining > 0x7FFFFFFF) {
+ if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_current)) {
+ return DR_FALSE;
+ }
+ bytesRemaining -= 0x7FFFFFFF;
+ }
+
+
+ if (bytesRemaining > 0) {
+ if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, drflac_seek_origin_current)) {
+ return DR_FALSE;
+ }
+ }
+ }
+ else
+ {
+ if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, drflac_seek_origin_start)) {
+ return DR_FALSE;
+ }
+ }
+
+
+ // The cache should be reset to force a reload of fresh data from the client.
+ drflac__reset_cache(bs);
+ return DR_TRUE;
+}
+
+
+static drBool32 drflac__read_utf8_coded_number(drflac_bs* bs, uint64_t* pNumberOut)
+{
+ assert(bs != NULL);
+ assert(pNumberOut != NULL);
+
+ unsigned char utf8[7] = {0};
+ if (!drflac__read_uint8(bs, 8, utf8)) {
+ *pNumberOut = 0;
+ return DR_FALSE;
+ }
+
+ if ((utf8[0] & 0x80) == 0) {
+ *pNumberOut = utf8[0];
+ return DR_TRUE;
+ }
+
+ int byteCount = 1;
+ if ((utf8[0] & 0xE0) == 0xC0) {
+ byteCount = 2;
+ } else if ((utf8[0] & 0xF0) == 0xE0) {
+ byteCount = 3;
+ } else if ((utf8[0] & 0xF8) == 0xF0) {
+ byteCount = 4;
+ } else if ((utf8[0] & 0xFC) == 0xF8) {
+ byteCount = 5;
+ } else if ((utf8[0] & 0xFE) == 0xFC) {
+ byteCount = 6;
+ } else if ((utf8[0] & 0xFF) == 0xFE) {
+ byteCount = 7;
+ } else {
+ *pNumberOut = 0;
+ return DR_FALSE; // Bad UTF-8 encoding.
+ }
+
+ // Read extra bytes.
+ assert(byteCount > 1);
+
+ uint64_t result = (uint64_t)(utf8[0] & (0xFF >> (byteCount + 1)));
+ for (int i = 1; i < byteCount; ++i) {
+ if (!drflac__read_uint8(bs, 8, utf8 + i)) {
+ *pNumberOut = 0;
+ return DR_FALSE;
+ }
+
+ result = (result << 6) | (utf8[i] & 0x3F);
+ }
+
+ *pNumberOut = result;
+ return DR_TRUE;
+}
+
+
+
+static DRFLAC_INLINE drBool32 drflac__read_and_seek_rice(drflac_bs* bs, uint8_t m)
+{
+ unsigned int unused;
+ if (!drflac__seek_past_next_set_bit(bs, &unused)) {
+ return DR_FALSE;
+ }
+
+ if (m > 0) {
+ if (!drflac__seek_bits(bs, m)) {
+ return DR_FALSE;
+ }
+ }
+
+ return DR_TRUE;
+}
+
+
+// The next two functions are responsible for calculating the prediction.
+//
+// When the bits per sample is >16 we need to use 64-bit integer arithmetic because otherwise we'll run out of precision. It's
+// safe to assume this will be slower on 32-bit platforms so we use a more optimal solution when the bits per sample is <=16.
+static DRFLAC_INLINE int32_t drflac__calculate_prediction_32(uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pDecodedSamples)
+{
+ assert(order <= 32);
+
+ // 32-bit version.
+
+ // VC++ optimizes this to a single jmp. I've not yet verified this for other compilers.
+ int32_t prediction = 0;
+
+ switch (order)
+ {
+ case 32: prediction += coefficients[31] * pDecodedSamples[-32];
+ case 31: prediction += coefficients[30] * pDecodedSamples[-31];
+ case 30: prediction += coefficients[29] * pDecodedSamples[-30];
+ case 29: prediction += coefficients[28] * pDecodedSamples[-29];
+ case 28: prediction += coefficients[27] * pDecodedSamples[-28];
+ case 27: prediction += coefficients[26] * pDecodedSamples[-27];
+ case 26: prediction += coefficients[25] * pDecodedSamples[-26];
+ case 25: prediction += coefficients[24] * pDecodedSamples[-25];
+ case 24: prediction += coefficients[23] * pDecodedSamples[-24];
+ case 23: prediction += coefficients[22] * pDecodedSamples[-23];
+ case 22: prediction += coefficients[21] * pDecodedSamples[-22];
+ case 21: prediction += coefficients[20] * pDecodedSamples[-21];
+ case 20: prediction += coefficients[19] * pDecodedSamples[-20];
+ case 19: prediction += coefficients[18] * pDecodedSamples[-19];
+ case 18: prediction += coefficients[17] * pDecodedSamples[-18];
+ case 17: prediction += coefficients[16] * pDecodedSamples[-17];
+ case 16: prediction += coefficients[15] * pDecodedSamples[-16];
+ case 15: prediction += coefficients[14] * pDecodedSamples[-15];
+ case 14: prediction += coefficients[13] * pDecodedSamples[-14];
+ case 13: prediction += coefficients[12] * pDecodedSamples[-13];
+ case 12: prediction += coefficients[11] * pDecodedSamples[-12];
+ case 11: prediction += coefficients[10] * pDecodedSamples[-11];
+ case 10: prediction += coefficients[ 9] * pDecodedSamples[-10];
+ case 9: prediction += coefficients[ 8] * pDecodedSamples[- 9];
+ case 8: prediction += coefficients[ 7] * pDecodedSamples[- 8];
+ case 7: prediction += coefficients[ 6] * pDecodedSamples[- 7];
+ case 6: prediction += coefficients[ 5] * pDecodedSamples[- 6];
+ case 5: prediction += coefficients[ 4] * pDecodedSamples[- 5];
+ case 4: prediction += coefficients[ 3] * pDecodedSamples[- 4];
+ case 3: prediction += coefficients[ 2] * pDecodedSamples[- 3];
+ case 2: prediction += coefficients[ 1] * pDecodedSamples[- 2];
+ case 1: prediction += coefficients[ 0] * pDecodedSamples[- 1];
+ }
+
+ return (int32_t)(prediction >> shift);
+}
+
+static DRFLAC_INLINE int32_t drflac__calculate_prediction_64(uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pDecodedSamples)
+{
+ assert(order <= 32);
+
+ // 64-bit version.
+
+ // This method is faster on the 32-bit build when compiling with VC++. See note below.
+#ifndef DRFLAC_64BIT
+ int64_t prediction;
+ if (order == 8)
+ {
+ prediction = coefficients[0] * (int64_t)pDecodedSamples[-1];
+ prediction += coefficients[1] * (int64_t)pDecodedSamples[-2];
+ prediction += coefficients[2] * (int64_t)pDecodedSamples[-3];
+ prediction += coefficients[3] * (int64_t)pDecodedSamples[-4];
+ prediction += coefficients[4] * (int64_t)pDecodedSamples[-5];
+ prediction += coefficients[5] * (int64_t)pDecodedSamples[-6];
+ prediction += coefficients[6] * (int64_t)pDecodedSamples[-7];
+ prediction += coefficients[7] * (int64_t)pDecodedSamples[-8];
+ }
+ else if (order == 7)
+ {
+ prediction = coefficients[0] * (int64_t)pDecodedSamples[-1];
+ prediction += coefficients[1] * (int64_t)pDecodedSamples[-2];
+ prediction += coefficients[2] * (int64_t)pDecodedSamples[-3];
+ prediction += coefficients[3] * (int64_t)pDecodedSamples[-4];
+ prediction += coefficients[4] * (int64_t)pDecodedSamples[-5];
+ prediction += coefficients[5] * (int64_t)pDecodedSamples[-6];
+ prediction += coefficients[6] * (int64_t)pDecodedSamples[-7];
+ }
+ else if (order == 3)
+ {
+ prediction = coefficients[0] * (int64_t)pDecodedSamples[-1];
+ prediction += coefficients[1] * (int64_t)pDecodedSamples[-2];
+ prediction += coefficients[2] * (int64_t)pDecodedSamples[-3];
+ }
+ else if (order == 6)
+ {
+ prediction = coefficients[0] * (int64_t)pDecodedSamples[-1];
+ prediction += coefficients[1] * (int64_t)pDecodedSamples[-2];
+ prediction += coefficients[2] * (int64_t)pDecodedSamples[-3];
+ prediction += coefficients[3] * (int64_t)pDecodedSamples[-4];
+ prediction += coefficients[4] * (int64_t)pDecodedSamples[-5];
+ prediction += coefficients[5] * (int64_t)pDecodedSamples[-6];
+ }
+ else if (order == 5)
+ {
+ prediction = coefficients[0] * (int64_t)pDecodedSamples[-1];
+ prediction += coefficients[1] * (int64_t)pDecodedSamples[-2];
+ prediction += coefficients[2] * (int64_t)pDecodedSamples[-3];
+ prediction += coefficients[3] * (int64_t)pDecodedSamples[-4];
+ prediction += coefficients[4] * (int64_t)pDecodedSamples[-5];
+ }
+ else if (order == 4)
+ {
+ prediction = coefficients[0] * (int64_t)pDecodedSamples[-1];
+ prediction += coefficients[1] * (int64_t)pDecodedSamples[-2];
+ prediction += coefficients[2] * (int64_t)pDecodedSamples[-3];
+ prediction += coefficients[3] * (int64_t)pDecodedSamples[-4];
+ }
+ else if (order == 12)
+ {
+ prediction = coefficients[0] * (int64_t)pDecodedSamples[-1];
+ prediction += coefficients[1] * (int64_t)pDecodedSamples[-2];
+ prediction += coefficients[2] * (int64_t)pDecodedSamples[-3];
+ prediction += coefficients[3] * (int64_t)pDecodedSamples[-4];
+ prediction += coefficients[4] * (int64_t)pDecodedSamples[-5];
+ prediction += coefficients[5] * (int64_t)pDecodedSamples[-6];
+ prediction += coefficients[6] * (int64_t)pDecodedSamples[-7];
+ prediction += coefficients[7] * (int64_t)pDecodedSamples[-8];
+ prediction += coefficients[8] * (int64_t)pDecodedSamples[-9];
+ prediction += coefficients[9] * (int64_t)pDecodedSamples[-10];
+ prediction += coefficients[10] * (int64_t)pDecodedSamples[-11];
+ prediction += coefficients[11] * (int64_t)pDecodedSamples[-12];
+ }
+ else if (order == 2)
+ {
+ prediction = coefficients[0] * (int64_t)pDecodedSamples[-1];
+ prediction += coefficients[1] * (int64_t)pDecodedSamples[-2];
+ }
+ else if (order == 1)
+ {
+ prediction = coefficients[0] * (int64_t)pDecodedSamples[-1];
+ }
+ else if (order == 10)
+ {
+ prediction = coefficients[0] * (int64_t)pDecodedSamples[-1];
+ prediction += coefficients[1] * (int64_t)pDecodedSamples[-2];
+ prediction += coefficients[2] * (int64_t)pDecodedSamples[-3];
+ prediction += coefficients[3] * (int64_t)pDecodedSamples[-4];
+ prediction += coefficients[4] * (int64_t)pDecodedSamples[-5];
+ prediction += coefficients[5] * (int64_t)pDecodedSamples[-6];
+ prediction += coefficients[6] * (int64_t)pDecodedSamples[-7];
+ prediction += coefficients[7] * (int64_t)pDecodedSamples[-8];
+ prediction += coefficients[8] * (int64_t)pDecodedSamples[-9];
+ prediction += coefficients[9] * (int64_t)pDecodedSamples[-10];
+ }
+ else if (order == 9)
+ {
+ prediction = coefficients[0] * (int64_t)pDecodedSamples[-1];
+ prediction += coefficients[1] * (int64_t)pDecodedSamples[-2];
+ prediction += coefficients[2] * (int64_t)pDecodedSamples[-3];
+ prediction += coefficients[3] * (int64_t)pDecodedSamples[-4];
+ prediction += coefficients[4] * (int64_t)pDecodedSamples[-5];
+ prediction += coefficients[5] * (int64_t)pDecodedSamples[-6];
+ prediction += coefficients[6] * (int64_t)pDecodedSamples[-7];
+ prediction += coefficients[7] * (int64_t)pDecodedSamples[-8];
+ prediction += coefficients[8] * (int64_t)pDecodedSamples[-9];
+ }
+ else if (order == 11)
+ {
+ prediction = coefficients[0] * (int64_t)pDecodedSamples[-1];
+ prediction += coefficients[1] * (int64_t)pDecodedSamples[-2];
+ prediction += coefficients[2] * (int64_t)pDecodedSamples[-3];
+ prediction += coefficients[3] * (int64_t)pDecodedSamples[-4];
+ prediction += coefficients[4] * (int64_t)pDecodedSamples[-5];
+ prediction += coefficients[5] * (int64_t)pDecodedSamples[-6];
+ prediction += coefficients[6] * (int64_t)pDecodedSamples[-7];
+ prediction += coefficients[7] * (int64_t)pDecodedSamples[-8];
+ prediction += coefficients[8] * (int64_t)pDecodedSamples[-9];
+ prediction += coefficients[9] * (int64_t)pDecodedSamples[-10];
+ prediction += coefficients[10] * (int64_t)pDecodedSamples[-11];
+ }
+ else
+ {
+ prediction = 0;
+ for (int j = 0; j < (int)order; ++j) {
+ prediction += coefficients[j] * (int64_t)pDecodedSamples[-j-1];
+ }
+ }
+#endif
+
+ // VC++ optimizes this to a single jmp instruction, but only the 64-bit build. The 32-bit build generates less efficient code for some
+ // reason. The ugly version above is faster so we'll just switch between the two depending on the target platform.
+#ifdef DRFLAC_64BIT
+ int64_t prediction = 0;
+
+ switch (order)
+ {
+ case 32: prediction += coefficients[31] * (int64_t)pDecodedSamples[-32];
+ case 31: prediction += coefficients[30] * (int64_t)pDecodedSamples[-31];
+ case 30: prediction += coefficients[29] * (int64_t)pDecodedSamples[-30];
+ case 29: prediction += coefficients[28] * (int64_t)pDecodedSamples[-29];
+ case 28: prediction += coefficients[27] * (int64_t)pDecodedSamples[-28];
+ case 27: prediction += coefficients[26] * (int64_t)pDecodedSamples[-27];
+ case 26: prediction += coefficients[25] * (int64_t)pDecodedSamples[-26];
+ case 25: prediction += coefficients[24] * (int64_t)pDecodedSamples[-25];
+ case 24: prediction += coefficients[23] * (int64_t)pDecodedSamples[-24];
+ case 23: prediction += coefficients[22] * (int64_t)pDecodedSamples[-23];
+ case 22: prediction += coefficients[21] * (int64_t)pDecodedSamples[-22];
+ case 21: prediction += coefficients[20] * (int64_t)pDecodedSamples[-21];
+ case 20: prediction += coefficients[19] * (int64_t)pDecodedSamples[-20];
+ case 19: prediction += coefficients[18] * (int64_t)pDecodedSamples[-19];
+ case 18: prediction += coefficients[17] * (int64_t)pDecodedSamples[-18];
+ case 17: prediction += coefficients[16] * (int64_t)pDecodedSamples[-17];
+ case 16: prediction += coefficients[15] * (int64_t)pDecodedSamples[-16];
+ case 15: prediction += coefficients[14] * (int64_t)pDecodedSamples[-15];
+ case 14: prediction += coefficients[13] * (int64_t)pDecodedSamples[-14];
+ case 13: prediction += coefficients[12] * (int64_t)pDecodedSamples[-13];
+ case 12: prediction += coefficients[11] * (int64_t)pDecodedSamples[-12];
+ case 11: prediction += coefficients[10] * (int64_t)pDecodedSamples[-11];
+ case 10: prediction += coefficients[ 9] * (int64_t)pDecodedSamples[-10];
+ case 9: prediction += coefficients[ 8] * (int64_t)pDecodedSamples[- 9];
+ case 8: prediction += coefficients[ 7] * (int64_t)pDecodedSamples[- 8];
+ case 7: prediction += coefficients[ 6] * (int64_t)pDecodedSamples[- 7];
+ case 6: prediction += coefficients[ 5] * (int64_t)pDecodedSamples[- 6];
+ case 5: prediction += coefficients[ 4] * (int64_t)pDecodedSamples[- 5];
+ case 4: prediction += coefficients[ 3] * (int64_t)pDecodedSamples[- 4];
+ case 3: prediction += coefficients[ 2] * (int64_t)pDecodedSamples[- 3];
+ case 2: prediction += coefficients[ 1] * (int64_t)pDecodedSamples[- 2];
+ case 1: prediction += coefficients[ 0] * (int64_t)pDecodedSamples[- 1];
+ }
+#endif
+
+ return (int32_t)(prediction >> shift);
+}
+
+
+// Reads and decodes a string of residual values as Rice codes. The decoder should be sitting on the first bit of the Rice codes.
+//
+// This is the most frequently called function in the library. It does both the Rice decoding and the prediction in a single loop
+// iteration. The prediction is done at the end, and there's an annoying branch I'd like to avoid so the main function is defined
+// as a #define - sue me!
+#define DRFLAC__DECODE_SAMPLES_WITH_RESIDULE__RICE__PROC(funcName, predictionFunc) \
+static drBool32 funcName (drflac_bs* bs, uint32_t count, uint8_t riceParam, uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pSamplesOut) \
+{ \
+ assert(bs != NULL); \
+ assert(count > 0); \
+ assert(pSamplesOut != NULL); \
+ \
+ static unsigned int bitOffsetTable[] = { \
+ 0, \
+ 4, \
+ 3, 3, \
+ 2, 2, 2, 2, \
+ 1, 1, 1, 1, 1, 1, 1, 1 \
+ }; \
+ \
+ drflac_cache_t riceParamMask = DRFLAC_CACHE_L1_SELECTION_MASK(riceParam); \
+ drflac_cache_t resultHiShift = DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceParam; \
+ \
+ for (int i = 0; i < (int)count; ++i) \
+ { \
+ unsigned int zeroCounter = 0; \
+ while (bs->cache == 0) { \
+ zeroCounter += (unsigned int)DRFLAC_CACHE_L1_BITS_REMAINING(bs); \
+ if (!drflac__reload_cache(bs)) { \
+ return DR_FALSE; \
+ } \
+ } \
+ \
+ /* At this point the cache should not be zero, in which case we know the first set bit should be somewhere in here. There is \
+ no need for us to perform any cache reloading logic here which should make things much faster. */ \
+ assert(bs->cache != 0); \
+ unsigned int decodedRice; \
+ \
+ unsigned int setBitOffsetPlus1 = bitOffsetTable[DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, 4)]; \
+ if (setBitOffsetPlus1 > 0) { \
+ decodedRice = (zeroCounter + (setBitOffsetPlus1-1)) << riceParam; \
+ } else { \
+ if (bs->cache == 1) { \
+ setBitOffsetPlus1 = DRFLAC_CACHE_L1_SIZE_BITS(bs); \
+ decodedRice = (zeroCounter + (DRFLAC_CACHE_L1_SIZE_BITS(bs)-1)) << riceParam; \
+ } else { \
+ setBitOffsetPlus1 = 5; \
+ for (;;) \
+ { \
+ if ((bs->cache & DRFLAC_CACHE_L1_SELECT(bs, setBitOffsetPlus1))) { \
+ decodedRice = (zeroCounter + (setBitOffsetPlus1-1)) << riceParam; \
+ break; \
+ } \
+ \
+ setBitOffsetPlus1 += 1; \
+ } \
+ } \
+ } \
+ \
+ \
+ unsigned int bitsLo = 0; \
+ unsigned int riceLength = setBitOffsetPlus1 + riceParam; \
+ if (riceLength < DRFLAC_CACHE_L1_BITS_REMAINING(bs)) \
+ { \
+ bitsLo = (unsigned int)((bs->cache & (riceParamMask >> setBitOffsetPlus1)) >> (DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceLength)); \
+ \
+ bs->consumedBits += riceLength; \
+ bs->cache <<= riceLength; \
+ } \
+ else \
+ { \
+ bs->consumedBits += riceLength; \
+ bs->cache <<= setBitOffsetPlus1; \
+ \
+ /* It straddles the cached data. It will never cover more than the next chunk. We just read the number in two parts and combine them. */ \
+ size_t bitCountLo = bs->consumedBits - DRFLAC_CACHE_L1_SIZE_BITS(bs); \
+ drflac_cache_t resultHi = bs->cache & riceParamMask; /* <-- This mask is OK because all bits after the first bits are always zero. */ \
+ \
+ \
+ if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { \
+ bs->cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); \
+ } else { \
+ /* Slow path. We need to fetch more data from the client. */ \
+ if (!drflac__reload_cache(bs)) { \
+ return DR_FALSE; \
+ } \
+ } \
+ \
+ bitsLo = (unsigned int)((resultHi >> resultHiShift) | DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountLo)); \
+ bs->consumedBits = bitCountLo; \
+ bs->cache <<= bitCountLo; \
+ } \
+ \
+ decodedRice |= bitsLo; \
+ decodedRice = (decodedRice >> 1) ^ (~(decodedRice & 0x01) + 1); /* <-- Ah, much faster! :) */ \
+ /* \
+ if ((decodedRice & 0x01)) { \
+ decodedRice = ~(decodedRice >> 1); \
+ } else { \
+ decodedRice = (decodedRice >> 1); \
+ } \
+ */ \
+ \
+ /* In order to properly calculate the prediction when the bits per sample is >16 we need to do it using 64-bit arithmetic. We can assume this \
+ is probably going to be slower on 32-bit systems so we'll do a more optimized 32-bit version when the bits per sample is low enough.*/ \
+ pSamplesOut[i] = ((int)decodedRice + predictionFunc(order, shift, coefficients, pSamplesOut + i)); \
+ } \
+ \
+ return DR_TRUE; \
+} \
+
+DRFLAC__DECODE_SAMPLES_WITH_RESIDULE__RICE__PROC(drflac__decode_samples_with_residual__rice_64, drflac__calculate_prediction_64)
+DRFLAC__DECODE_SAMPLES_WITH_RESIDULE__RICE__PROC(drflac__decode_samples_with_residual__rice_32, drflac__calculate_prediction_32)
+
+
+// Reads and seeks past a string of residual values as Rice codes. The decoder should be sitting on the first bit of the Rice codes.
+static drBool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, uint32_t count, uint8_t riceParam)
+{
+ assert(bs != NULL);
+ assert(count > 0);
+
+ for (uint32_t i = 0; i < count; ++i) {
+ if (!drflac__read_and_seek_rice(bs, riceParam)) {
+ return DR_FALSE;
+ }
+ }
+
+ return DR_TRUE;
+}
+
+static drBool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* bs, uint32_t bitsPerSample, uint32_t count, uint8_t unencodedBitsPerSample, uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pSamplesOut)
+{
+ assert(bs != NULL);
+ assert(count > 0);
+ assert(unencodedBitsPerSample > 0 && unencodedBitsPerSample <= 32);
+ assert(pSamplesOut != NULL);
+
+ for (unsigned int i = 0; i < count; ++i)
+ {
+ if (!drflac__read_int32(bs, unencodedBitsPerSample, pSamplesOut + i)) {
+ return DR_FALSE;
+ }
+
+ if (bitsPerSample > 16) {
+ pSamplesOut[i] += drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + i);
+ } else {
+ pSamplesOut[i] += drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + i);
+ }
+ }
+
+ return DR_TRUE;
+}
+
+
+// Reads and decodes the residual for the sub-frame the decoder is currently sitting on. This function should be called
+// when the decoder is sitting at the very start of the RESIDUAL block. The first <order> residuals will be ignored. The
+// <blockSize> and <order> parameters are used to determine how many residual values need to be decoded.
+static drBool32 drflac__decode_samples_with_residual(drflac_bs* bs, uint32_t bitsPerSample, uint32_t blockSize, uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pDecodedSamples)
+{
+ assert(bs != NULL);
+ assert(blockSize != 0);
+ assert(pDecodedSamples != NULL); // <-- Should we allow NULL, in which case we just seek past the residual rather than do a full decode?
+
+ uint8_t residualMethod;
+ if (!drflac__read_uint8(bs, 2, &residualMethod)) {
+ return DR_FALSE;
+ }
+
+ if (residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
+ return DR_FALSE; // Unknown or unsupported residual coding method.
+ }
+
+ // Ignore the first <order> values.
+ pDecodedSamples += order;
+
+
+ uint8_t partitionOrder;
+ if (!drflac__read_uint8(bs, 4, &partitionOrder)) {
+ return DR_FALSE;
+ }
+
+
+ uint32_t samplesInPartition = (blockSize / (1 << partitionOrder)) - order;
+ uint32_t partitionsRemaining = (1 << partitionOrder);
+ for (;;)
+ {
+ uint8_t riceParam = 0;
+ if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) {
+ if (!drflac__read_uint8(bs, 4, &riceParam)) {
+ return DR_FALSE;
+ }
+ if (riceParam == 16) {
+ riceParam = 0xFF;
+ }
+ } else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
+ if (!drflac__read_uint8(bs, 5, &riceParam)) {
+ return DR_FALSE;
+ }
+ if (riceParam == 32) {
+ riceParam = 0xFF;
+ }
+ }
+
+ if (riceParam != 0xFF) {
+ if (bitsPerSample > 16) {
+ if (!drflac__decode_samples_with_residual__rice_64(bs, samplesInPartition, riceParam, order, shift, coefficients, pDecodedSamples)) {
+ return DR_FALSE;
+ }
+ } else {
+ if (!drflac__decode_samples_with_residual__rice_32(bs, samplesInPartition, riceParam, order, shift, coefficients, pDecodedSamples)) {
+ return DR_FALSE;
+ }
+ }
+ } else {
+ unsigned char unencodedBitsPerSample = 0;
+ if (!drflac__read_uint8(bs, 5, &unencodedBitsPerSample)) {
+ return DR_FALSE;
+ }
+
+ if (!drflac__decode_samples_with_residual__unencoded(bs, bitsPerSample, samplesInPartition, unencodedBitsPerSample, order, shift, coefficients, pDecodedSamples)) {
+ return DR_FALSE;
+ }
+ }
+
+ pDecodedSamples += samplesInPartition;
+
+
+ if (partitionsRemaining == 1) {
+ break;
+ }
+
+ partitionsRemaining -= 1;
+ samplesInPartition = blockSize / (1 << partitionOrder);
+ }
+
+ return DR_TRUE;
+}
+
+// Reads and seeks past the residual for the sub-frame the decoder is currently sitting on. This function should be called
+// when the decoder is sitting at the very start of the RESIDUAL block. The first <order> residuals will be set to 0. The
+// <blockSize> and <order> parameters are used to determine how many residual values need to be decoded.
+static drBool32 drflac__read_and_seek_residual(drflac_bs* bs, uint32_t blockSize, uint32_t order)
+{
+ assert(bs != NULL);
+ assert(blockSize != 0);
+
+ uint8_t residualMethod;
+ if (!drflac__read_uint8(bs, 2, &residualMethod)) {
+ return DR_FALSE;
+ }
+
+ if (residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
+ return DR_FALSE; // Unknown or unsupported residual coding method.
+ }
+
+ uint8_t partitionOrder;
+ if (!drflac__read_uint8(bs, 4, &partitionOrder)) {
+ return DR_FALSE;
+ }
+
+ uint32_t samplesInPartition = (blockSize / (1 << partitionOrder)) - order;
+ uint32_t partitionsRemaining = (1 << partitionOrder);
+ for (;;)
+ {
+ uint8_t riceParam = 0;
+ if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) {
+ if (!drflac__read_uint8(bs, 4, &riceParam)) {
+ return DR_FALSE;
+ }
+ if (riceParam == 16) {
+ riceParam = 0xFF;
+ }
+ } else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
+ if (!drflac__read_uint8(bs, 5, &riceParam)) {
+ return DR_FALSE;
+ }
+ if (riceParam == 32) {
+ riceParam = 0xFF;
+ }
+ }
+
+ if (riceParam != 0xFF) {
+ if (!drflac__read_and_seek_residual__rice(bs, samplesInPartition, riceParam)) {
+ return DR_FALSE;
+ }
+ } else {
+ unsigned char unencodedBitsPerSample = 0;
+ if (!drflac__read_uint8(bs, 5, &unencodedBitsPerSample)) {
+ return DR_FALSE;
+ }
+
+ if (!drflac__seek_bits(bs, unencodedBitsPerSample * samplesInPartition)) {
+ return DR_FALSE;
+ }
+ }
+
+
+ if (partitionsRemaining == 1) {
+ break;
+ }
+
+ partitionsRemaining -= 1;
+ samplesInPartition = blockSize / (1 << partitionOrder);
+ }
+
+ return DR_TRUE;
+}
+
+
+static drBool32 drflac__decode_samples__constant(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, int32_t* pDecodedSamples)
+{
+ // Only a single sample needs to be decoded here.
+ int32_t sample;
+ if (!drflac__read_int32(bs, bitsPerSample, &sample)) {
+ return DR_FALSE;
+ }
+
+ // We don't really need to expand this, but it does simplify the process of reading samples. If this becomes a performance issue (unlikely)
+ // we'll want to look at a more efficient way.
+ for (uint32_t i = 0; i < blockSize; ++i) {
+ pDecodedSamples[i] = sample;
+ }
+
+ return DR_TRUE;
+}
+
+static drBool32 drflac__decode_samples__verbatim(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, int32_t* pDecodedSamples)
+{
+ for (uint32_t i = 0; i < blockSize; ++i) {
+ int32_t sample;
+ if (!drflac__read_int32(bs, bitsPerSample, &sample)) {
+ return DR_FALSE;
+ }
+
+ pDecodedSamples[i] = sample;
+ }
+
+ return DR_TRUE;
+}
+
+static drBool32 drflac__decode_samples__fixed(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, uint8_t lpcOrder, int32_t* pDecodedSamples)
+{
+ short lpcCoefficientsTable[5][4] = {
+ {0, 0, 0, 0},
+ {1, 0, 0, 0},
+ {2, -1, 0, 0},
+ {3, -3, 1, 0},
+ {4, -6, 4, -1}
+ };
+
+ // Warm up samples and coefficients.
+ for (uint32_t i = 0; i < lpcOrder; ++i) {
+ int32_t sample;
+ if (!drflac__read_int32(bs, bitsPerSample, &sample)) {
+ return DR_FALSE;
+ }
+
+ pDecodedSamples[i] = sample;
+ }
+
+
+ if (!drflac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, 0, lpcCoefficientsTable[lpcOrder], pDecodedSamples)) {
+ return DR_FALSE;
+ }
+
+ return DR_TRUE;
+}
+
+static drBool32 drflac__decode_samples__lpc(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, uint8_t lpcOrder, int32_t* pDecodedSamples)
+{
+ // Warm up samples.
+ for (uint8_t i = 0; i < lpcOrder; ++i) {
+ int32_t sample;
+ if (!drflac__read_int32(bs, bitsPerSample, &sample)) {
+ return DR_FALSE;
+ }
+
+ pDecodedSamples[i] = sample;
+ }
+
+ uint8_t lpcPrecision;
+ if (!drflac__read_uint8(bs, 4, &lpcPrecision)) {
+ return DR_FALSE;
+ }
+ if (lpcPrecision == 15) {
+ return DR_FALSE; // Invalid.
+ }
+ lpcPrecision += 1;
+
+
+ int8_t lpcShift;
+ if (!drflac__read_int8(bs, 5, &lpcShift)) {
+ return DR_FALSE;
+ }
+
+
+ int16_t coefficients[32];
+ for (uint8_t i = 0; i < lpcOrder; ++i) {
+ if (!drflac__read_int16(bs, lpcPrecision, coefficients + i)) {
+ return DR_FALSE;
+ }
+ }
+
+ if (!drflac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, lpcShift, coefficients, pDecodedSamples)) {
+ return DR_FALSE;
+ }
+
+ return DR_TRUE;
+}
+
+
+static drBool32 drflac__read_next_frame_header(drflac_bs* bs, uint8_t streaminfoBitsPerSample, drflac_frame_header* header)
+{
+ assert(bs != NULL);
+ assert(header != NULL);
+
+ // At the moment the sync code is as a form of basic validation. The CRC is stored, but is unused at the moment. This
+ // should probably be handled better in the future.
+
+ const uint32_t sampleRateTable[12] = {0, 88200, 176400, 192000, 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000};
+ const uint8_t bitsPerSampleTable[8] = {0, 8, 12, (uint8_t)-1, 16, 20, 24, (uint8_t)-1}; // -1 = reserved.
+
+ uint16_t syncCode = 0;
+ if (!drflac__read_uint16(bs, 14, &syncCode)) {
+ return DR_FALSE;
+ }
+
+ if (syncCode != 0x3FFE) {
+ // TODO: Try and recover by attempting to seek to and read the next frame?
+ return DR_FALSE;
+ }
+
+ uint8_t reserved;
+ if (!drflac__read_uint8(bs, 1, &reserved)) {
+ return DR_FALSE;
+ }
+
+ uint8_t blockingStrategy = 0;
+ if (!drflac__read_uint8(bs, 1, &blockingStrategy)) {
+ return DR_FALSE;
+ }
+
+
+
+ uint8_t blockSize = 0;
+ if (!drflac__read_uint8(bs, 4, &blockSize)) {
+ return DR_FALSE;
+ }
+
+ uint8_t sampleRate = 0;
+ if (!drflac__read_uint8(bs, 4, &sampleRate)) {
+ return DR_FALSE;
+ }
+
+ uint8_t channelAssignment = 0;
+ if (!drflac__read_uint8(bs, 4, &channelAssignment)) {
+ return DR_FALSE;
+ }
+
+ uint8_t bitsPerSample = 0;
+ if (!drflac__read_uint8(bs, 3, &bitsPerSample)) {
+ return DR_FALSE;
+ }
+
+ if (!drflac__read_uint8(bs, 1, &reserved)) {
+ return DR_FALSE;
+ }
+
+
+ drBool32 isVariableBlockSize = blockingStrategy == 1;
+ if (isVariableBlockSize) {
+ uint64_t sampleNumber;
+ if (!drflac__read_utf8_coded_number(bs, &sampleNumber)) {
+ return DR_FALSE;
+ }
+ header->frameNumber = 0;
+ header->sampleNumber = sampleNumber;
+ } else {
+ uint64_t frameNumber = 0;
+ if (!drflac__read_utf8_coded_number(bs, &frameNumber)) {
+ return DR_FALSE;
+ }
+ header->frameNumber = (uint32_t)frameNumber; // <-- Safe cast.
+ header->sampleNumber = 0;
+ }
+
+
+ if (blockSize == 1) {
+ header->blockSize = 192;
+ } else if (blockSize >= 2 && blockSize <= 5) {
+ header->blockSize = 576 * (1 << (blockSize - 2));
+ } else if (blockSize == 6) {
+ if (!drflac__read_uint16(bs, 8, &header->blockSize)) {
+ return DR_FALSE;
+ }
+ header->blockSize += 1;
+ } else if (blockSize == 7) {
+ if (!drflac__read_uint16(bs, 16, &header->blockSize)) {
+ return DR_FALSE;
+ }
+ header->blockSize += 1;
+ } else {
+ header->blockSize = 256 * (1 << (blockSize - 8));
+ }
+
+
+ if (sampleRate <= 11) {
+ header->sampleRate = sampleRateTable[sampleRate];
+ } else if (sampleRate == 12) {
+ if (!drflac__read_uint32(bs, 8, &header->sampleRate)) {
+ return DR_FALSE;
+ }
+ header->sampleRate *= 1000;
+ } else if (sampleRate == 13) {
+ if (!drflac__read_uint32(bs, 16, &header->sampleRate)) {
+ return DR_FALSE;
+ }
+ } else if (sampleRate == 14) {
+ if (!drflac__read_uint32(bs, 16, &header->sampleRate)) {
+ return DR_FALSE;
+ }
+ header->sampleRate *= 10;
+ } else {
+ return DR_FALSE; // Invalid.
+ }
+
+
+ header->channelAssignment = channelAssignment;
+
+ header->bitsPerSample = bitsPerSampleTable[bitsPerSample];
+ if (header->bitsPerSample == 0) {
+ header->bitsPerSample = streaminfoBitsPerSample;
+ }
+
+ if (drflac__read_uint8(bs, 8, &header->crc8) != 1) {
+ return DR_FALSE;
+ }
+
+ return DR_TRUE;
+}
+
+static drBool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe* pSubframe)
+{
+ uint8_t header;
+ if (!drflac__read_uint8(bs, 8, &header)) {
+ return DR_FALSE;
+ }
+
+ // First bit should always be 0.
+ if ((header & 0x80) != 0) {
+ return DR_FALSE;
+ }
+
+ int type = (header & 0x7E) >> 1;
+ if (type == 0) {
+ pSubframe->subframeType = DRFLAC_SUBFRAME_CONSTANT;
+ } else if (type == 1) {
+ pSubframe->subframeType = DRFLAC_SUBFRAME_VERBATIM;
+ } else {
+ if ((type & 0x20) != 0) {
+ pSubframe->subframeType = DRFLAC_SUBFRAME_LPC;
+ pSubframe->lpcOrder = (type & 0x1F) + 1;
+ } else if ((type & 0x08) != 0) {
+ pSubframe->subframeType = DRFLAC_SUBFRAME_FIXED;
+ pSubframe->lpcOrder = (type & 0x07);
+ if (pSubframe->lpcOrder > 4) {
+ pSubframe->subframeType = DRFLAC_SUBFRAME_RESERVED;
+ pSubframe->lpcOrder = 0;
+ }
+ } else {
+ pSubframe->subframeType = DRFLAC_SUBFRAME_RESERVED;
+ }
+ }
+
+ if (pSubframe->subframeType == DRFLAC_SUBFRAME_RESERVED) {
+ return DR_FALSE;
+ }
+
+ // Wasted bits per sample.
+ pSubframe->wastedBitsPerSample = 0;
+ if ((header & 0x01) == 1) {
+ unsigned int wastedBitsPerSample;
+ if (!drflac__seek_past_next_set_bit(bs, &wastedBitsPerSample)) {
+ return DR_FALSE;
+ }
+ pSubframe->wastedBitsPerSample = (unsigned char)wastedBitsPerSample + 1;
+ }
+
+ return DR_TRUE;
+}
+
+static drBool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex, int32_t* pDecodedSamplesOut)
+{
+ assert(bs != NULL);
+ assert(frame != NULL);
+
+ drflac_subframe* pSubframe = frame->subframes + subframeIndex;
+ if (!drflac__read_subframe_header(bs, pSubframe)) {
+ return DR_FALSE;
+ }
+
+ // Side channels require an extra bit per sample. Took a while to figure that one out...
+ pSubframe->bitsPerSample = frame->header.bitsPerSample;
+ if ((frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) {
+ pSubframe->bitsPerSample += 1;
+ } else if (frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) {
+ pSubframe->bitsPerSample += 1;
+ }
+
+ // Need to handle wasted bits per sample.
+ pSubframe->bitsPerSample -= pSubframe->wastedBitsPerSample;
+ pSubframe->pDecodedSamples = pDecodedSamplesOut;
+
+ switch (pSubframe->subframeType)
+ {
+ case DRFLAC_SUBFRAME_CONSTANT:
+ {
+ drflac__decode_samples__constant(bs, frame->header.blockSize, pSubframe->bitsPerSample, pSubframe->pDecodedSamples);
+ } break;
+
+ case DRFLAC_SUBFRAME_VERBATIM:
+ {
+ drflac__decode_samples__verbatim(bs, frame->header.blockSize, pSubframe->bitsPerSample, pSubframe->pDecodedSamples);
+ } break;
+
+ case DRFLAC_SUBFRAME_FIXED:
+ {
+ drflac__decode_samples__fixed(bs, frame->header.blockSize, pSubframe->bitsPerSample, pSubframe->lpcOrder, pSubframe->pDecodedSamples);
+ } break;
+
+ case DRFLAC_SUBFRAME_LPC:
+ {
+ drflac__decode_samples__lpc(bs, frame->header.blockSize, pSubframe->bitsPerSample, pSubframe->lpcOrder, pSubframe->pDecodedSamples);
+ } break;
+
+ default: return DR_FALSE;
+ }
+
+ return DR_TRUE;
+}
+
+static drBool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex)
+{
+ assert(bs != NULL);
+ assert(frame != NULL);
+
+ drflac_subframe* pSubframe = frame->subframes + subframeIndex;
+ if (!drflac__read_subframe_header(bs, pSubframe)) {
+ return DR_FALSE;
+ }
+
+ // Side channels require an extra bit per sample. Took a while to figure that one out...
+ pSubframe->bitsPerSample = frame->header.bitsPerSample;
+ if ((frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) {
+ pSubframe->bitsPerSample += 1;
+ } else if (frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) {
+ pSubframe->bitsPerSample += 1;
+ }
+
+ // Need to handle wasted bits per sample.
+ pSubframe->bitsPerSample -= pSubframe->wastedBitsPerSample;
+ pSubframe->pDecodedSamples = NULL;
+ //pSubframe->pDecodedSamples = pFlac->pDecodedSamples + (pFlac->currentFrame.header.blockSize * subframeIndex);
+
+ switch (pSubframe->subframeType)
+ {
+ case DRFLAC_SUBFRAME_CONSTANT:
+ {
+ if (!drflac__seek_bits(bs, pSubframe->bitsPerSample)) {
+ return DR_FALSE;
+ }
+ } break;
+
+ case DRFLAC_SUBFRAME_VERBATIM:
+ {
+ unsigned int bitsToSeek = frame->header.blockSize * pSubframe->bitsPerSample;
+ if (!drflac__seek_bits(bs, bitsToSeek)) {
+ return DR_FALSE;
+ }
+ } break;
+
+ case DRFLAC_SUBFRAME_FIXED:
+ {
+ unsigned int bitsToSeek = pSubframe->lpcOrder * pSubframe->bitsPerSample;
+ if (!drflac__seek_bits(bs, bitsToSeek)) {
+ return DR_FALSE;
+ }
+
+ if (!drflac__read_and_seek_residual(bs, frame->header.blockSize, pSubframe->lpcOrder)) {
+ return DR_FALSE;
+ }
+ } break;
+
+ case DRFLAC_SUBFRAME_LPC:
+ {
+ unsigned int bitsToSeek = pSubframe->lpcOrder * pSubframe->bitsPerSample;
+ if (!drflac__seek_bits(bs, bitsToSeek)) {
+ return DR_FALSE;
+ }
+
+ unsigned char lpcPrecision;
+ if (!drflac__read_uint8(bs, 4, &lpcPrecision)) {
+ return DR_FALSE;
+ }
+ if (lpcPrecision == 15) {
+ return DR_FALSE; // Invalid.
+ }
+ lpcPrecision += 1;
+
+
+ bitsToSeek = (pSubframe->lpcOrder * lpcPrecision) + 5; // +5 for shift.
+ if (!drflac__seek_bits(bs, bitsToSeek)) {
+ return DR_FALSE;
+ }
+
+ if (!drflac__read_and_seek_residual(bs, frame->header.blockSize, pSubframe->lpcOrder)) {
+ return DR_FALSE;
+ }
+ } break;
+
+ default: return DR_FALSE;
+ }
+
+ return DR_TRUE;
+}
+
+
+static DRFLAC_INLINE uint8_t drflac__get_channel_count_from_channel_assignment(int8_t channelAssignment)
+{
+ assert(channelAssignment <= 10);
+
+ uint8_t lookup[] = {1, 2, 3, 4, 5, 6, 7, 8, 2, 2, 2};
+ return lookup[channelAssignment];
+}
+
+static drBool32 drflac__decode_frame(drflac* pFlac)
+{
+ // This function should be called while the stream is sitting on the first byte after the frame header.
+ memset(pFlac->currentFrame.subframes, 0, sizeof(pFlac->currentFrame.subframes));
+
+ int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment);
+ for (int i = 0; i < channelCount; ++i)
+ {
+ if (!drflac__decode_subframe(&pFlac->bs, &pFlac->currentFrame, i, pFlac->pDecodedSamples + (pFlac->currentFrame.header.blockSize * i))) {
+ return DR_FALSE;
+ }
+ }
+
+ // At the end of the frame sits the padding and CRC. We don't use these so we can just seek past.
+ if (!drflac__seek_bits(&pFlac->bs, (DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7) + 16)) {
+ return DR_FALSE;
+ }
+
+
+ pFlac->currentFrame.samplesRemaining = pFlac->currentFrame.header.blockSize * channelCount;
+
+ return DR_TRUE;
+}
+
+static drBool32 drflac__seek_frame(drflac* pFlac)
+{
+ int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment);
+ for (int i = 0; i < channelCount; ++i)
+ {
+ if (!drflac__seek_subframe(&pFlac->bs, &pFlac->currentFrame, i)) {
+ return DR_FALSE;
+ }
+ }
+
+ // Padding and CRC.
+ return drflac__seek_bits(&pFlac->bs, (DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7) + 16);
+}
+
+static drBool32 drflac__read_and_decode_next_frame(drflac* pFlac)
+{
+ assert(pFlac != NULL);
+
+ if (!drflac__read_next_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFrame.header)) {
+ return DR_FALSE;
+ }
+
+ return drflac__decode_frame(pFlac);
+}
+
+
+static void drflac__get_current_frame_sample_range(drflac* pFlac, uint64_t* pFirstSampleInFrameOut, uint64_t* pLastSampleInFrameOut)
+{
+ assert(pFlac != NULL);
+
+ unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment);
+
+ uint64_t firstSampleInFrame = pFlac->currentFrame.header.sampleNumber;
+ if (firstSampleInFrame == 0) {
+ firstSampleInFrame = pFlac->currentFrame.header.frameNumber * pFlac->maxBlockSize*channelCount;
+ }
+
+ uint64_t lastSampleInFrame = firstSampleInFrame + (pFlac->currentFrame.header.blockSize*channelCount);
+ if (lastSampleInFrame > 0) {
+ lastSampleInFrame -= 1; // Needs to be zero based.
+ }
+
+
+ if (pFirstSampleInFrameOut) {
+ *pFirstSampleInFrameOut = firstSampleInFrame;
+ }
+ if (pLastSampleInFrameOut) {
+ *pLastSampleInFrameOut = lastSampleInFrame;
+ }
+}
+
+static drBool32 drflac__seek_to_first_frame(drflac* pFlac)
+{
+ assert(pFlac != NULL);
+
+ drBool32 result = drflac__seek_to_byte(&pFlac->bs, pFlac->firstFramePos);
+
+ memset(&pFlac->currentFrame, 0, sizeof(pFlac->currentFrame));
+ return result;
+}
+
+static DRFLAC_INLINE drBool32 drflac__seek_to_next_frame(drflac* pFlac)
+{
+ // This function should only ever be called while the decoder is sitting on the first byte past the FRAME_HEADER section.
+ assert(pFlac != NULL);
+ return drflac__seek_frame(pFlac);
+}
+
+static drBool32 drflac__seek_to_frame_containing_sample(drflac* pFlac, uint64_t sampleIndex)
+{
+ assert(pFlac != NULL);
+
+ if (!drflac__seek_to_first_frame(pFlac)) {
+ return DR_FALSE;
+ }
+
+ uint64_t firstSampleInFrame = 0;
+ uint64_t lastSampleInFrame = 0;
+ for (;;)
+ {
+ // We need to read the frame's header in order to determine the range of samples it contains.
+ if (!drflac__read_next_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFrame.header)) {
+ return DR_FALSE;
+ }
+
+ drflac__get_current_frame_sample_range(pFlac, &firstSampleInFrame, &lastSampleInFrame);
+ if (sampleIndex >= firstSampleInFrame && sampleIndex <= lastSampleInFrame) {
+ break; // The sample is in this frame.
+ }
+
+ if (!drflac__seek_to_next_frame(pFlac)) {
+ return DR_FALSE;
+ }
+ }
+
+ // If we get here we should be right at the start of the frame containing the sample.
+ return DR_TRUE;
+}
+
+static drBool32 drflac__seek_to_sample__brute_force(drflac* pFlac, uint64_t sampleIndex)
+{
+ if (!drflac__seek_to_frame_containing_sample(pFlac, sampleIndex)) {
+ return DR_FALSE;
+ }
+
+ // At this point we should be sitting on the first byte of the frame containing the sample. We need to decode every sample up to (but
+ // not including) the sample we're seeking to.
+ uint64_t firstSampleInFrame = 0;
+ drflac__get_current_frame_sample_range(pFlac, &firstSampleInFrame, NULL);
+
+ assert(firstSampleInFrame <= sampleIndex);
+ size_t samplesToDecode = (size_t)(sampleIndex - firstSampleInFrame); // <-- Safe cast because the maximum number of samples in a frame is 65535.
+ if (samplesToDecode == 0) {
+ return DR_TRUE;
+ }
+
+ // At this point we are just sitting on the byte after the frame header. We need to decode the frame before reading anything from it.
+ if (!drflac__decode_frame(pFlac)) {
+ return DR_FALSE;
+ }
+
+ return drflac_read_s32(pFlac, samplesToDecode, NULL) != 0;
+}
+
+
+static drBool32 drflac__seek_to_sample__seek_table(drflac* pFlac, uint64_t sampleIndex)
+{
+ assert(pFlac != NULL);
+
+ if (pFlac->seektablePos == 0) {
+ return DR_FALSE;
+ }
+
+ if (!drflac__seek_to_byte(&pFlac->bs, pFlac->seektablePos)) {
+ return DR_FALSE;
+ }
+
+ // The number of seek points is derived from the size of the SEEKTABLE block.
+ uint32_t seekpointCount = pFlac->seektableSize / 18; // 18 = the size of each seek point.
+ if (seekpointCount == 0) {
+ return DR_FALSE; // Would this ever happen?
+ }
+
+
+ drflac_seekpoint closestSeekpoint = {0, 0, 0};
+
+ uint32_t seekpointsRemaining = seekpointCount;
+ while (seekpointsRemaining > 0)
+ {
+ drflac_seekpoint seekpoint;
+ if (!drflac__read_uint64(&pFlac->bs, 64, &seekpoint.firstSample)) {
+ break;
+ }
+ if (!drflac__read_uint64(&pFlac->bs, 64, &seekpoint.frameOffset)) {
+ break;
+ }
+ if (!drflac__read_uint16(&pFlac->bs, 16, &seekpoint.sampleCount)) {
+ break;
+ }
+
+ if (seekpoint.firstSample * pFlac->channels > sampleIndex) {
+ break;
+ }
+
+ closestSeekpoint = seekpoint;
+ seekpointsRemaining -= 1;
+ }
+
+ // At this point we should have found the seekpoint closest to our sample. We need to seek to it using basically the same
+ // technique as we use with the brute force method.
+ if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFramePos + closestSeekpoint.frameOffset)) {
+ return DR_FALSE;
+ }
+
+
+ uint64_t firstSampleInFrame = 0;
+ uint64_t lastSampleInFrame = 0;
+ for (;;)
+ {
+ // We need to read the frame's header in order to determine the range of samples it contains.
+ if (!drflac__read_next_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFrame.header)) {
+ return DR_FALSE;
+ }
+
+ drflac__get_current_frame_sample_range(pFlac, &firstSampleInFrame, &lastSampleInFrame);
+ if (sampleIndex >= firstSampleInFrame && sampleIndex <= lastSampleInFrame) {
+ break; // The sample is in this frame.
+ }
+
+ if (!drflac__seek_to_next_frame(pFlac)) {
+ return DR_FALSE;
+ }
+ }
+
+ assert(firstSampleInFrame <= sampleIndex);
+
+ // At this point we are just sitting on the byte after the frame header. We need to decode the frame before reading anything from it.
+ if (!drflac__decode_frame(pFlac)) {
+ return DR_FALSE;
+ }
+
+ size_t samplesToDecode = (size_t)(sampleIndex - firstSampleInFrame); // <-- Safe cast because the maximum number of samples in a frame is 65535.
+ return drflac_read_s32(pFlac, samplesToDecode, NULL) == samplesToDecode;
+}
+
+
+#ifndef DR_FLAC_NO_OGG
+typedef struct
+{
+ uint8_t capturePattern[4]; // Should be "OggS"
+ uint8_t structureVersion; // Always 0.
+ uint8_t headerType;
+ uint64_t granulePosition;
+ uint32_t serialNumber;
+ uint32_t sequenceNumber;
+ uint32_t checksum;
+ uint8_t segmentCount;
+ uint8_t segmentTable[255];
+} drflac_ogg_page_header;
+#endif
+
+typedef struct
+{
+ drflac_read_proc onRead;
+ drflac_seek_proc onSeek;
+ drflac_meta_proc onMeta;
+ void* pUserData;
+ void* pUserDataMD;
+ drflac_container container;
+ uint32_t sampleRate;
+ uint8_t channels;
+ uint8_t bitsPerSample;
+ uint64_t totalSampleCount;
+ uint16_t maxBlockSize;
+ uint64_t runningFilePos;
+ drBool32 hasMetadataBlocks;
+
+#ifndef DR_FLAC_NO_OGG
+ uint32_t oggSerial;
+ uint64_t oggFirstBytePos;
+ drflac_ogg_page_header oggBosHeader;
+#endif
+} drflac_init_info;
+
+static DRFLAC_INLINE void drflac__decode_block_header(uint32_t blockHeader, uint8_t* isLastBlock, uint8_t* blockType, uint32_t* blockSize)
+{
+ blockHeader = drflac__be2host_32(blockHeader);
+ *isLastBlock = (blockHeader & (0x01 << 31)) >> 31;
+ *blockType = (blockHeader & (0x7F << 24)) >> 24;
+ *blockSize = (blockHeader & 0xFFFFFF);
+}
+
+static DRFLAC_INLINE drBool32 drflac__read_and_decode_block_header(drflac_read_proc onRead, void* pUserData, uint8_t* isLastBlock, uint8_t* blockType, uint32_t* blockSize)
+{
+ uint32_t blockHeader;
+ if (onRead(pUserData, &blockHeader, 4) != 4) {
+ return DR_FALSE;
+ }
+
+ drflac__decode_block_header(blockHeader, isLastBlock, blockType, blockSize);
+ return DR_TRUE;
+}
+
+drBool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, drflac_streaminfo* pStreamInfo)
+{
+ // min/max block size.
+ uint32_t blockSizes;
+ if (onRead(pUserData, &blockSizes, 4) != 4) {
+ return DR_FALSE;
+ }
+
+ // min/max frame size.
+ uint64_t frameSizes = 0;
+ if (onRead(pUserData, &frameSizes, 6) != 6) {
+ return DR_FALSE;
+ }
+
+ // Sample rate, channels, bits per sample and total sample count.
+ uint64_t importantProps;
+ if (onRead(pUserData, &importantProps, 8) != 8) {
+ return DR_FALSE;
+ }
+
+ // MD5
+ uint8_t md5[16];
+ if (onRead(pUserData, md5, sizeof(md5)) != sizeof(md5)) {
+ return DR_FALSE;
+ }
+
+ blockSizes = drflac__be2host_32(blockSizes);
+ frameSizes = drflac__be2host_64(frameSizes);
+ importantProps = drflac__be2host_64(importantProps);
+
+ pStreamInfo->minBlockSize = (blockSizes & 0xFFFF0000) >> 16;
+ pStreamInfo->maxBlockSize = blockSizes & 0x0000FFFF;
+ pStreamInfo->minFrameSize = (uint32_t)((frameSizes & 0xFFFFFF0000000000ULL) >> 40ULL);
+ pStreamInfo->maxFrameSize = (uint32_t)((frameSizes & 0x000000FFFFFF0000ULL) >> 16ULL);
+ pStreamInfo->sampleRate = (uint32_t)((importantProps & 0xFFFFF00000000000ULL) >> 44ULL);
+ pStreamInfo->channels = (uint8_t )((importantProps & 0x00000E0000000000ULL) >> 41ULL) + 1;
+ pStreamInfo->bitsPerSample = (uint8_t )((importantProps & 0x000001F000000000ULL) >> 36ULL) + 1;
+ pStreamInfo->totalSampleCount = (importantProps & 0x0000000FFFFFFFFFULL) * pStreamInfo->channels;
+ memcpy(pStreamInfo->md5, md5, sizeof(md5));
+
+ return DR_TRUE;
+}
+
+drBool32 drflac__read_and_decode_metadata(drflac* pFlac)
+{
+ assert(pFlac != NULL);
+
+ // We want to keep track of the byte position in the stream of the seektable. At the time of calling this function we know that
+ // we'll be sitting on byte 42.
+ uint64_t runningFilePos = 42;
+ uint64_t seektablePos = 0;
+ uint32_t seektableSize = 0;
+
+ for (;;)
+ {
+ uint8_t isLastBlock = 0;
+ uint8_t blockType;
+ uint32_t blockSize;
+ if (!drflac__read_and_decode_block_header(pFlac->bs.onRead, pFlac->bs.pUserData, &isLastBlock, &blockType, &blockSize)) {
+ return DR_FALSE;
+ }
+ runningFilePos += 4;
+
+
+ drflac_metadata metadata;
+ metadata.type = blockType;
+ metadata.pRawData = NULL;
+ metadata.rawDataSize = 0;
+
+ switch (blockType)
+ {
+ case DRFLAC_METADATA_BLOCK_TYPE_APPLICATION:
+ {
+ if (pFlac->onMeta) {
+ void* pRawData = malloc(blockSize);
+ if (pRawData == NULL) {
+ return DR_FALSE;
+ }
+
+ if (pFlac->bs.onRead(pFlac->bs.pUserData, pRawData, blockSize) != blockSize) {
+ free(pRawData);
+ return DR_FALSE;
+ }
+
+ metadata.pRawData = pRawData;
+ metadata.rawDataSize = blockSize;
+ metadata.data.application.id = drflac__be2host_32(*(uint32_t*)pRawData);
+ metadata.data.application.pData = (const void*)((uint8_t*)pRawData + sizeof(uint32_t));
+ metadata.data.application.dataSize = blockSize - sizeof(uint32_t);
+ pFlac->onMeta(pFlac->pUserDataMD, &metadata);
+
+ free(pRawData);
+ }
+ } break;
+
+ case DRFLAC_METADATA_BLOCK_TYPE_SEEKTABLE:
+ {
+ seektablePos = runningFilePos;
+ seektableSize = blockSize;
+
+ if (pFlac->onMeta) {
+ void* pRawData = malloc(blockSize);
+ if (pRawData == NULL) {
+ return DR_FALSE;
+ }
+
+ if (pFlac->bs.onRead(pFlac->bs.pUserData, pRawData, blockSize) != blockSize) {
+ free(pRawData);
+ return DR_FALSE;
+ }
+
+ metadata.pRawData = pRawData;
+ metadata.rawDataSize = blockSize;
+ metadata.data.seektable.seekpointCount = blockSize/sizeof(drflac_seekpoint);
+ metadata.data.seektable.pSeekpoints = (const drflac_seekpoint*)pRawData;
+
+ // Endian swap.
+ for (uint32_t iSeekpoint = 0; iSeekpoint < metadata.data.seektable.seekpointCount; ++iSeekpoint) {
+ drflac_seekpoint* pSeekpoint = (drflac_seekpoint*)pRawData + iSeekpoint;
+ pSeekpoint->firstSample = drflac__be2host_64(pSeekpoint->firstSample);
+ pSeekpoint->frameOffset = drflac__be2host_64(pSeekpoint->frameOffset);
+ pSeekpoint->sampleCount = drflac__be2host_16(pSeekpoint->sampleCount);
+ }
+
+ pFlac->onMeta(pFlac->pUserDataMD, &metadata);
+
+ free(pRawData);
+ }
+ } break;
+
+ case DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT:
+ {
+ if (pFlac->onMeta) {
+ void* pRawData = malloc(blockSize);
+ if (pRawData == NULL) {
+ return DR_FALSE;
+ }
+
+ if (pFlac->bs.onRead(pFlac->bs.pUserData, pRawData, blockSize) != blockSize) {
+ free(pRawData);
+ return DR_FALSE;
+ }
+
+ metadata.pRawData = pRawData;
+ metadata.rawDataSize = blockSize;
+
+ const char* pRunningData = (const char*)pRawData;
+ metadata.data.vorbis_comment.vendorLength = drflac__le2host_32(*(uint32_t*)pRunningData); pRunningData += 4;
+ metadata.data.vorbis_comment.vendor = pRunningData; pRunningData += metadata.data.vorbis_comment.vendorLength;
+ metadata.data.vorbis_comment.commentCount = drflac__le2host_32(*(uint32_t*)pRunningData); pRunningData += 4;
+ metadata.data.vorbis_comment.comments = pRunningData;
+ pFlac->onMeta(pFlac->pUserDataMD, &metadata);
+
+ free(pRawData);
+ }
+ } break;
+
+ case DRFLAC_METADATA_BLOCK_TYPE_CUESHEET:
+ {
+ if (pFlac->onMeta) {
+ void* pRawData = malloc(blockSize);
+ if (pRawData == NULL) {
+ return DR_FALSE;
+ }
+
+ if (pFlac->bs.onRead(pFlac->bs.pUserData, pRawData, blockSize) != blockSize) {
+ free(pRawData);
+ return DR_FALSE;
+ }
+
+ metadata.pRawData = pRawData;
+ metadata.rawDataSize = blockSize;
+
+ const char* pRunningData = (const char*)pRawData;
+ memcpy(metadata.data.cuesheet.catalog, pRunningData, 128); pRunningData += 128;
+ metadata.data.cuesheet.leadInSampleCount = drflac__be2host_64(*(uint64_t*)pRunningData); pRunningData += 4;
+ metadata.data.cuesheet.isCD = ((pRunningData[0] & 0x80) >> 7) != 0; pRunningData += 259;
+ metadata.data.cuesheet.trackCount = pRunningData[0]; pRunningData += 1;
+ metadata.data.cuesheet.pTrackData = (const uint8_t*)pRunningData;
+ pFlac->onMeta(pFlac->pUserDataMD, &metadata);
+
+ free(pRawData);
+ }
+ } break;
+
+ case DRFLAC_METADATA_BLOCK_TYPE_PICTURE:
+ {
+ if (pFlac->onMeta) {
+ void* pRawData = malloc(blockSize);
+ if (pRawData == NULL) {
+ return DR_FALSE;
+ }
+
+ if (pFlac->bs.onRead(pFlac->bs.pUserData, pRawData, blockSize) != blockSize) {
+ free(pRawData);
+ return DR_FALSE;
+ }
+
+ metadata.pRawData = pRawData;
+ metadata.rawDataSize = blockSize;
+
+ const char* pRunningData = (const char*)pRawData;
+ metadata.data.picture.type = drflac__be2host_32(*(uint32_t*)pRunningData); pRunningData += 4;
+ metadata.data.picture.mimeLength = drflac__be2host_32(*(uint32_t*)pRunningData); pRunningData += 4;
+ metadata.data.picture.mime = pRunningData; pRunningData += metadata.data.picture.mimeLength;
+ metadata.data.picture.descriptionLength = drflac__be2host_32(*(uint32_t*)pRunningData); pRunningData += 4;
+ metadata.data.picture.description = pRunningData;
+ metadata.data.picture.width = drflac__be2host_32(*(uint32_t*)pRunningData); pRunningData += 4;
+ metadata.data.picture.height = drflac__be2host_32(*(uint32_t*)pRunningData); pRunningData += 4;
+ metadata.data.picture.colorDepth = drflac__be2host_32(*(uint32_t*)pRunningData); pRunningData += 4;
+ metadata.data.picture.indexColorCount = drflac__be2host_32(*(uint32_t*)pRunningData); pRunningData += 4;
+ metadata.data.picture.pictureDataSize = drflac__be2host_32(*(uint32_t*)pRunningData); pRunningData += 4;
+ metadata.data.picture.pPictureData = (const uint8_t*)pRunningData;
+ pFlac->onMeta(pFlac->pUserDataMD, &metadata);
+
+ free(pRawData);
+ }
+ } break;
+
+ case DRFLAC_METADATA_BLOCK_TYPE_PADDING:
+ {
+ if (pFlac->onMeta) {
+ metadata.data.padding.unused = 0;
+
+ // Padding doesn't have anything meaningful in it, so just skip over it.
+ if (!pFlac->bs.onSeek(pFlac->bs.pUserData, blockSize, drflac_seek_origin_current)) {
+ return DR_FALSE;
+ }
+
+ pFlac->onMeta(pFlac->pUserDataMD, &metadata);
+ }
+ } break;
+
+ case DRFLAC_METADATA_BLOCK_TYPE_INVALID:
+ {
+ // Invalid chunk. Just skip over this one.
+ if (pFlac->onMeta) {
+ if (!pFlac->bs.onSeek(pFlac->bs.pUserData, blockSize, drflac_seek_origin_current)) {
+ return DR_FALSE;
+ }
+ }
+ }
+
+ default:
+ {
+ // It's an unknown chunk, but not necessarily invalid. There's a chance more metadata blocks might be defined later on, so we
+ // can at the very least report the chunk to the application and let it look at the raw data.
+ if (pFlac->onMeta) {
+ void* pRawData = malloc(blockSize);
+ if (pRawData == NULL) {
+ return DR_FALSE;
+ }
+
+ if (pFlac->bs.onRead(pFlac->bs.pUserData, pRawData, blockSize) != blockSize) {
+ free(pRawData);
+ return DR_FALSE;
+ }
+
+ metadata.pRawData = pRawData;
+ metadata.rawDataSize = blockSize;
+ pFlac->onMeta(pFlac->pUserDataMD, &metadata);
+
+ free(pRawData);
+ }
+ } break;
+ }
+
+ // If we're not handling metadata, just skip over the block. If we are, it will have been handled earlier in the switch statement above.
+ if (pFlac->onMeta == NULL) {
+ if (!pFlac->bs.onSeek(pFlac->bs.pUserData, blockSize, drflac_seek_origin_current)) {
+ return DR_FALSE;
+ }
+ }
+
+ runningFilePos += blockSize;
+ if (isLastBlock) {
+ break;
+ }
+ }
+
+ pFlac->seektablePos = seektablePos;
+ pFlac->seektableSize = seektableSize;
+ pFlac->firstFramePos = runningFilePos;
+
+ return DR_TRUE;
+}
+
+drBool32 drflac__init_private__native(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD)
+{
+ (void)onSeek;
+
+ // Pre: The bit stream should be sitting just past the 4-byte id header.
+
+ pInit->container = drflac_container_native;
+
+ // The first metadata block should be the STREAMINFO block.
+ uint8_t isLastBlock;
+ uint8_t blockType;
+ uint32_t blockSize;
+ if (!drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize)) {
+ return DR_FALSE;
+ }
+
+ if (blockType != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) {
+ return DR_FALSE; // Invalid block type. First block must be the STREAMINFO block.
+ }
+
+
+ drflac_streaminfo streaminfo;
+ if (!drflac__read_streaminfo(onRead, pUserData, &streaminfo)) {
+ return DR_FALSE;
+ }
+
+ pInit->sampleRate = streaminfo.sampleRate;
+ pInit->channels = streaminfo.channels;
+ pInit->bitsPerSample = streaminfo.bitsPerSample;
+ pInit->totalSampleCount = streaminfo.totalSampleCount;
+ pInit->maxBlockSize = streaminfo.maxBlockSize; // Don't care about the min block size - only the max (used for determining the size of the memory allocation).
+
+ if (onMeta) {
+ drflac_metadata metadata;
+ metadata.type = DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO;
+ metadata.pRawData = NULL;
+ metadata.rawDataSize = 0;
+ metadata.data.streaminfo = streaminfo;
+ onMeta(pUserDataMD, &metadata);
+ }
+
+ pInit->hasMetadataBlocks = !isLastBlock;
+ return DR_TRUE;
+}
+
+#ifndef DR_FLAC_NO_OGG
+static DRFLAC_INLINE drBool32 drflac_ogg__is_capture_pattern(uint8_t pattern[4])
+{
+ return pattern[0] == 'O' && pattern[1] == 'g' && pattern[2] == 'g' && pattern[3] == 'S';
+}
+
+static DRFLAC_INLINE uint32_t drflac_ogg__get_page_header_size(drflac_ogg_page_header* pHeader)
+{
+ return 27 + pHeader->segmentCount;
+}
+
+static DRFLAC_INLINE uint32_t drflac_ogg__get_page_body_size(drflac_ogg_page_header* pHeader)
+{
+ uint32_t pageBodySize = 0;
+ for (int i = 0; i < pHeader->segmentCount; ++i) {
+ pageBodySize += pHeader->segmentTable[i];
+ }
+
+ return pageBodySize;
+}
+
+drBool32 drflac_ogg__read_page_header_after_capture_pattern(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, uint32_t* pHeaderSize)
+{
+ if (onRead(pUserData, &pHeader->structureVersion, 1) != 1 || pHeader->structureVersion != 0) {
+ return DR_FALSE; // Unknown structure version. Possibly corrupt stream.
+ }
+ if (onRead(pUserData, &pHeader->headerType, 1) != 1) {
+ return DR_FALSE;
+ }
+ if (onRead(pUserData, &pHeader->granulePosition, 8) != 8) {
+ return DR_FALSE;
+ }
+ if (onRead(pUserData, &pHeader->serialNumber, 4) != 4) {
+ return DR_FALSE;
+ }
+ if (onRead(pUserData, &pHeader->sequenceNumber, 4) != 4) {
+ return DR_FALSE;
+ }
+ if (onRead(pUserData, &pHeader->checksum, 4) != 4) {
+ return DR_FALSE;
+ }
+ if (onRead(pUserData, &pHeader->segmentCount, 1) != 1 || pHeader->segmentCount == 0) {
+ return DR_FALSE; // Should not have a segment count of 0.
+ }
+ if (onRead(pUserData, &pHeader->segmentTable, pHeader->segmentCount) != pHeader->segmentCount) {
+ return DR_FALSE;
+ }
+
+ if (pHeaderSize) *pHeaderSize = (27 + pHeader->segmentCount);
+ return DR_TRUE;
+}
+
+drBool32 drflac_ogg__read_page_header(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, uint32_t* pHeaderSize)
+{
+ uint8_t id[4];
+ if (onRead(pUserData, id, 4) != 4) {
+ return DR_FALSE;
+ }
+
+ if (id[0] != 'O' || id[1] != 'g' || id[2] != 'g' || id[3] != 'S') {
+ return DR_FALSE;
+ }
+
+ return drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, pHeader, pHeaderSize);
+}
+
+
+// The main part of the Ogg encapsulation is the conversion from the physical Ogg bitstream to the native FLAC bitstream. It works
+// in three general stages: Ogg Physical Bitstream -> Ogg/FLAC Logical Bitstream -> FLAC Native Bitstream. dr_flac is architecured
+// in such a way that the core sections assume everything is delivered in native format. Therefore, for each encapsulation type
+// dr_flac is supporting there needs to be a layer sitting on top of the onRead and onSeek callbacks that ensures the bits read from
+// the physical Ogg bitstream are converted and delivered in native FLAC format.
+typedef struct
+{
+ drflac_read_proc onRead; // The original onRead callback from drflac_open() and family.
+ drflac_seek_proc onSeek; // The original onSeek callback from drflac_open() and family.
+ void* pUserData; // The user data passed on onRead and onSeek. This is the user data that was passed on drflac_open() and family.
+ uint64_t currentBytePos; // The position of the byte we are sitting on in the physical byte stream. Used for efficient seeking.
+ uint64_t firstBytePos; // The position of the first byte in the physical bitstream. Points to the start of the "OggS" identifier of the FLAC bos page.
+ uint32_t serialNumber; // The serial number of the FLAC audio pages. This is determined by the initial header page that was read during initialization.
+ drflac_ogg_page_header bosPageHeader; // Used for seeking.
+ drflac_ogg_page_header currentPageHeader;
+ uint32_t bytesRemainingInPage;
+} drflac_oggbs; // oggbs = Ogg Bitstream
+
+static size_t drflac_oggbs__read_physical(drflac_oggbs* oggbs, void* bufferOut, size_t bytesToRead)
+{
+ size_t bytesActuallyRead = oggbs->onRead(oggbs->pUserData, bufferOut, bytesToRead);
+ oggbs->currentBytePos += bytesActuallyRead;
+
+ return bytesActuallyRead;
+}
+
+static drBool32 drflac_oggbs__seek_physical(drflac_oggbs* oggbs, uint64_t offset, drflac_seek_origin origin)
+{
+ if (origin == drflac_seek_origin_start)
+ {
+ if (offset <= 0x7FFFFFFF) {
+ if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_start)) {
+ return DR_FALSE;
+ }
+ oggbs->currentBytePos = offset;
+
+ return DR_TRUE;
+ } else {
+ if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) {
+ return DR_FALSE;
+ }
+ oggbs->currentBytePos = offset;
+
+ return drflac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, drflac_seek_origin_current);
+ }
+ }
+ else
+ {
+ while (offset > 0x7FFFFFFF) {
+ if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, drflac_seek_origin_current)) {
+ return DR_FALSE;
+ }
+ oggbs->currentBytePos += 0x7FFFFFFF;
+ offset -= 0x7FFFFFFF;
+ }
+
+ if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_current)) { // <-- Safe cast thanks to the loop above.
+ return DR_FALSE;
+ }
+ oggbs->currentBytePos += offset;
+
+ return DR_TRUE;
+ }
+}
+
+static drBool32 drflac_oggbs__goto_next_page(drflac_oggbs* oggbs)
+{
+ drflac_ogg_page_header header;
+ for (;;)
+ {
+ uint32_t headerSize;
+ if (!drflac_ogg__read_page_header(oggbs->onRead, oggbs->pUserData, &header, &headerSize)) {
+ return DR_FALSE;
+ }
+ oggbs->currentBytePos += headerSize;
+
+
+ uint32_t pageBodySize = drflac_ogg__get_page_body_size(&header);
+
+ if (header.serialNumber == oggbs->serialNumber) {
+ oggbs->currentPageHeader = header;
+ oggbs->bytesRemainingInPage = pageBodySize;
+ return DR_TRUE;
+ }
+
+ // If we get here it means the page is not a FLAC page - skip it.
+ if (pageBodySize > 0 && !drflac_oggbs__seek_physical(oggbs, pageBodySize, drflac_seek_origin_current)) { // <-- Safe cast - maximum size of a page is way below that of an int.
+ return DR_FALSE;
+ }
+ }
+}
+
+// Function below is unused at the moment, but I might be re-adding it later.
+#if 0
+static uint8_t drflac_oggbs__get_current_segment_index(drflac_oggbs* oggbs, uint8_t* pBytesRemainingInSeg)
+{
+ uint32_t bytesConsumedInPage = drflac_ogg__get_page_body_size(&oggbs->currentPageHeader) - oggbs->bytesRemainingInPage;
+ uint8_t iSeg = 0;
+ uint32_t iByte = 0;
+ while (iByte < bytesConsumedInPage)
+ {
+ uint8_t segmentSize = oggbs->currentPageHeader.segmentTable[iSeg];
+ if (iByte + segmentSize > bytesConsumedInPage) {
+ break;
+ } else {
+ iSeg += 1;
+ iByte += segmentSize;
+ }
+ }
+
+ *pBytesRemainingInSeg = oggbs->currentPageHeader.segmentTable[iSeg] - (uint8_t)(bytesConsumedInPage - iByte);
+ return iSeg;
+}
+
+static drBool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs)
+{
+ // The current packet ends when we get to the segment with a lacing value of < 255 which is not at the end of a page.
+ for (;;) // <-- Loop over pages.
+ {
+ drBool32 atEndOfPage = DR_FALSE;
+
+ uint8_t bytesRemainingInSeg;
+ uint8_t iFirstSeg = drflac_oggbs__get_current_segment_index(oggbs, &bytesRemainingInSeg);
+
+ uint32_t bytesToEndOfPacketOrPage = bytesRemainingInSeg;
+ for (uint8_t iSeg = iFirstSeg; iSeg < oggbs->currentPageHeader.segmentCount; ++iSeg) {
+ uint8_t segmentSize = oggbs->currentPageHeader.segmentTable[iSeg];
+ if (segmentSize < 255) {
+ if (iSeg == oggbs->currentPageHeader.segmentCount-1) {
+ atEndOfPage = DR_TRUE;
+ }
+
+ break;
+ }
+
+ bytesToEndOfPacketOrPage += segmentSize;
+ }
+
+ // At this point we will have found either the packet or the end of the page. If were at the end of the page we'll
+ // want to load the next page and keep searching for the end of the frame.
+ drflac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, drflac_seek_origin_current);
+ oggbs->bytesRemainingInPage -= bytesToEndOfPacketOrPage;
+
+ if (atEndOfPage)
+ {
+ // We're potentially at the next packet, but we need to check the next page first to be sure because the packet may
+ // straddle pages.
+ if (!drflac_oggbs__goto_next_page(oggbs)) {
+ return DR_FALSE;
+ }
+
+ // If it's a fresh packet it most likely means we're at the next packet.
+ if ((oggbs->currentPageHeader.headerType & 0x01) == 0) {
+ return DR_TRUE;
+ }
+ }
+ else
+ {
+ // We're at the next frame.
+ return DR_TRUE;
+ }
+ }
+}
+
+static drBool32 drflac_oggbs__seek_to_next_frame(drflac_oggbs* oggbs)
+{
+ // The bitstream should be sitting on the first byte just after the header of the frame.
+
+ // What we're actually doing here is seeking to the start of the next packet.
+ return drflac_oggbs__seek_to_next_packet(oggbs);
+}
+#endif
+
+static size_t drflac__on_read_ogg(void* pUserData, void* bufferOut, size_t bytesToRead)
+{
+ drflac_oggbs* oggbs = (drflac_oggbs*)pUserData;
+ assert(oggbs != NULL);
+
+ uint8_t* pRunningBufferOut = (uint8_t*)bufferOut;
+
+ // Reading is done page-by-page. If we've run out of bytes in the page we need to move to the next one.
+ size_t bytesRead = 0;
+ while (bytesRead < bytesToRead)
+ {
+ size_t bytesRemainingToRead = bytesToRead - bytesRead;
+
+ if (oggbs->bytesRemainingInPage >= bytesRemainingToRead) {
+ bytesRead += oggbs->onRead(oggbs->pUserData, pRunningBufferOut, bytesRemainingToRead);
+ oggbs->bytesRemainingInPage -= (uint32_t)bytesRemainingToRead;
+ break;
+ }
+
+ // If we get here it means some of the requested data is contained in the next pages.
+ if (oggbs->bytesRemainingInPage > 0) {
+ size_t bytesJustRead = oggbs->onRead(oggbs->pUserData, pRunningBufferOut, oggbs->bytesRemainingInPage);
+ bytesRead += bytesJustRead;
+ pRunningBufferOut += bytesJustRead;
+
+ if (bytesJustRead != oggbs->bytesRemainingInPage) {
+ break; // Ran out of data.
+ }
+ }
+
+ assert(bytesRemainingToRead > 0);
+ if (!drflac_oggbs__goto_next_page(oggbs)) {
+ break; // Failed to go to the next chunk. Might have simply hit the end of the stream.
+ }
+ }
+
+ oggbs->currentBytePos += bytesRead;
+ return bytesRead;
+}
+
+static drBool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_seek_origin origin)
+{
+ drflac_oggbs* oggbs = (drflac_oggbs*)pUserData;
+ assert(oggbs != NULL);
+ assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start));
+
+ // Seeking is always forward which makes things a lot simpler.
+ if (origin == drflac_seek_origin_start) {
+ int startBytePos = (int)oggbs->firstBytePos + (79-42); // 79 = size of bos page; 42 = size of FLAC header data. Seek up to the first byte of the native FLAC data.
+ if (!drflac_oggbs__seek_physical(oggbs, startBytePos, drflac_seek_origin_start)) {
+ return DR_FALSE;
+ }
+
+ oggbs->currentPageHeader = oggbs->bosPageHeader;
+ oggbs->bytesRemainingInPage = 42; // 42 = size of the native FLAC header data. That's our start point for seeking.
+
+ return drflac__on_seek_ogg(pUserData, offset, drflac_seek_origin_current);
+ }
+
+
+ assert(origin == drflac_seek_origin_current);
+
+ int bytesSeeked = 0;
+ while (bytesSeeked < offset)
+ {
+ int bytesRemainingToSeek = offset - bytesSeeked;
+ assert(bytesRemainingToSeek >= 0);
+
+ if (oggbs->bytesRemainingInPage >= (size_t)bytesRemainingToSeek) {
+ if (!drflac_oggbs__seek_physical(oggbs, bytesRemainingToSeek, drflac_seek_origin_current)) {
+ return DR_FALSE;
+ }
+
+ bytesSeeked += bytesRemainingToSeek;
+ oggbs->bytesRemainingInPage -= bytesRemainingToSeek;
+ break;
+ }
+
+ // If we get here it means some of the requested data is contained in the next pages.
+ if (oggbs->bytesRemainingInPage > 0) {
+ if (!drflac_oggbs__seek_physical(oggbs, oggbs->bytesRemainingInPage, drflac_seek_origin_current)) {
+ return DR_FALSE;
+ }
+
+ bytesSeeked += (int)oggbs->bytesRemainingInPage;
+ }
+
+ assert(bytesRemainingToSeek > 0);
+ if (!drflac_oggbs__goto_next_page(oggbs)) {
+ break; // Failed to go to the next chunk. Might have simply hit the end of the stream.
+ }
+ }
+
+ return DR_TRUE;
+}
+
+drBool32 drflac_ogg__seek_to_sample(drflac* pFlac, uint64_t sample)
+{
+ drflac_oggbs* oggbs = (drflac_oggbs*)(((int32_t*)pFlac->pExtraData) + pFlac->maxBlockSize*pFlac->channels);
+
+ uint64_t originalBytePos = oggbs->currentBytePos; // For recovery.
+
+ // First seek to the first frame.
+ if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFramePos)) {
+ return DR_FALSE;
+ }
+ oggbs->bytesRemainingInPage = 0;
+
+ uint64_t runningGranulePosition = 0;
+ uint64_t runningFrameBytePos = oggbs->currentBytePos; // <-- Points to the OggS identifier.
+ for (;;)
+ {
+ if (!drflac_oggbs__goto_next_page(oggbs)) {
+ drflac_oggbs__seek_physical(oggbs, originalBytePos, drflac_seek_origin_start);
+ return DR_FALSE; // Never did find that sample...
+ }
+
+ runningFrameBytePos = oggbs->currentBytePos - drflac_ogg__get_page_header_size(&oggbs->currentPageHeader);
+ if (oggbs->currentPageHeader.granulePosition*pFlac->channels >= sample) {
+ break; // The sample is somewhere in the previous page.
+ }
+
+
+ // At this point we know the sample is not in the previous page. It could possibly be in this page. For simplicity we
+ // disregard any pages that do not begin a fresh packet.
+ if ((oggbs->currentPageHeader.headerType & 0x01) == 0) { // <-- Is it a fresh page?
+ if (oggbs->currentPageHeader.segmentTable[0] >= 2) {
+ uint8_t firstBytesInPage[2];
+ if (drflac_oggbs__read_physical(oggbs, firstBytesInPage, 2) != 2) {
+ drflac_oggbs__seek_physical(oggbs, originalBytePos, drflac_seek_origin_start);
+ return DR_FALSE;
+ }
+ if ((firstBytesInPage[0] == 0xFF) && (firstBytesInPage[1] & 0xFC) == 0xF8) { // <-- Does the page begin with a frame's sync code?
+ runningGranulePosition = oggbs->currentPageHeader.granulePosition*pFlac->channels;
+ }
+
+ if (!drflac_oggbs__seek_physical(oggbs, (int)oggbs->bytesRemainingInPage-2, drflac_seek_origin_current)) {
+ drflac_oggbs__seek_physical(oggbs, originalBytePos, drflac_seek_origin_start);
+ return DR_FALSE;
+ }
+
+ continue;
+ }
+ }
+
+ if (!drflac_oggbs__seek_physical(oggbs, (int)oggbs->bytesRemainingInPage, drflac_seek_origin_current)) {
+ drflac_oggbs__seek_physical(oggbs, originalBytePos, drflac_seek_origin_start);
+ return DR_FALSE;
+ }
+ }
+
+
+ // We found the page that that is closest to the sample, so now we need to find it. The first thing to do is seek to the
+ // start of that page. In the loop above we checked that it was a fresh page which means this page is also the start of
+ // a new frame. This property means that after we've seeked to the page we can immediately start looping over frames until
+ // we find the one containing the target sample.
+ if (!drflac_oggbs__seek_physical(oggbs, runningFrameBytePos, drflac_seek_origin_start)) {
+ return DR_FALSE;
+ }
+ if (!drflac_oggbs__goto_next_page(oggbs)) {
+ return DR_FALSE;
+ }
+
+
+ // At this point we'll be sitting on the first byte of the frame header of the first frame in the page. We just keep
+ // looping over these frames until we find the one containing the sample we're after.
+ uint64_t firstSampleInFrame = runningGranulePosition;
+ for (;;)
+ {
+ // NOTE for later: When using Ogg's page/segment based seeking later on we can't use this function (or any drflac__*
+ // reading functions) because otherwise it will pull extra data for use in it's own internal caches which will then
+ // break the positioning of the read pointer for the Ogg bitstream.
+ if (!drflac__read_next_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFrame.header)) {
+ return DR_FALSE;
+ }
+
+ int channels = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment);
+ uint64_t lastSampleInFrame = firstSampleInFrame + (pFlac->currentFrame.header.blockSize*channels);
+ lastSampleInFrame -= 1; // <-- Zero based.
+
+ if (sample >= firstSampleInFrame && sample <= lastSampleInFrame) {
+ break; // The sample is in this frame.
+ }
+
+
+ // If we get here it means the sample is not in this frame so we need to move to the next one. Now the cool thing
+ // with Ogg is that we can efficiently seek past the frame by looking at the lacing values of each segment in
+ // the page.
+ firstSampleInFrame = lastSampleInFrame+1;
+
+#if 1
+ // Slow way. This uses the native FLAC decoder to seek past the frame. This is slow because it needs to do a partial
+ // decode of the frame. Although this is how the native version works, we can use Ogg's framing system to make it
+ // more efficient. Leaving this here for reference and to use as a basis for debugging purposes.
+ if (!drflac__seek_to_next_frame(pFlac)) {
+ return DR_FALSE;
+ }
+#else
+ // TODO: This is not yet complete. See note at the top of this loop body.
+
+ // Fast(er) way. This uses Ogg's framing system to seek past the frame. This should be much more efficient than the
+ // native FLAC seeking.
+ if (!drflac_oggbs__seek_to_next_frame(oggbs)) {
+ return DR_FALSE;
+ }
+#endif
+ }
+
+ assert(firstSampleInFrame <= sample);
+
+ if (!drflac__decode_frame(pFlac)) {
+ return DR_FALSE;
+ }
+
+ size_t samplesToDecode = (size_t)(sample - firstSampleInFrame); // <-- Safe cast because the maximum number of samples in a frame is 65535.
+ return drflac_read_s32(pFlac, samplesToDecode, NULL) == samplesToDecode;
+}
+
+
+drBool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD)
+{
+ // Pre: The bit stream should be sitting just past the 4-byte OggS capture pattern.
+
+ pInit->container = drflac_container_ogg;
+ pInit->oggFirstBytePos = 0;
+
+ // We'll get here if the first 4 bytes of the stream were the OggS capture pattern, however it doesn't necessarily mean the
+ // stream includes FLAC encoded audio. To check for this we need to scan the beginning-of-stream page markers and check if
+ // any match the FLAC specification. Important to keep in mind that the stream may be multiplexed.
+ drflac_ogg_page_header header;
+
+ uint32_t headerSize;
+ if (!drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, &header, &headerSize)) {
+ return DR_FALSE;
+ }
+ pInit->runningFilePos = headerSize;
+
+ for (;;)
+ {
+ // Break if we're past the beginning of stream page.
+ if ((header.headerType & 0x02) == 0) {
+ return DR_FALSE;
+ }
+
+
+ // Check if it's a FLAC header.
+ int pageBodySize = drflac_ogg__get_page_body_size(&header);
+ if (pageBodySize == 51) // 51 = the lacing value of the FLAC header packet.
+ {
+ // It could be a FLAC page...
+ uint32_t bytesRemainingInPage = pageBodySize;
+
+ uint8_t packetType;
+ if (onRead(pUserData, &packetType, 1) != 1) {
+ return DR_FALSE;
+ }
+
+ bytesRemainingInPage -= 1;
+ if (packetType == 0x7F)
+ {
+ // Increasingly more likely to be a FLAC page...
+ uint8_t sig[4];
+ if (onRead(pUserData, sig, 4) != 4) {
+ return DR_FALSE;
+ }
+
+ bytesRemainingInPage -= 4;
+ if (sig[0] == 'F' && sig[1] == 'L' && sig[2] == 'A' && sig[3] == 'C')
+ {
+ // Almost certainly a FLAC page...
+ uint8_t mappingVersion[2];
+ if (onRead(pUserData, mappingVersion, 2) != 2) {
+ return DR_FALSE;
+ }
+
+ if (mappingVersion[0] != 1) {
+ return DR_FALSE; // Only supporting version 1.x of the Ogg mapping.
+ }
+
+ // The next 2 bytes are the non-audio packets, not including this one. We don't care about this because we're going to
+ // be handling it in a generic way based on the serial number and packet types.
+ if (!onSeek(pUserData, 2, drflac_seek_origin_current)) {
+ return DR_FALSE;
+ }
+
+ // Expecting the native FLAC signature "fLaC".
+ if (onRead(pUserData, sig, 4) != 4) {
+ return DR_FALSE;
+ }
+
+ if (sig[0] == 'f' && sig[1] == 'L' && sig[2] == 'a' && sig[3] == 'C')
+ {
+ // The remaining data in the page should be the STREAMINFO block.
+ uint8_t isLastBlock;
+ uint8_t blockType;
+ uint32_t blockSize;
+ if (!drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize)) {
+ return DR_FALSE;
+ }
+
+ if (blockType != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) {
+ return DR_FALSE; // Invalid block type. First block must be the STREAMINFO block.
+ }
+
+ drflac_streaminfo streaminfo;
+ if (drflac__read_streaminfo(onRead, pUserData, &streaminfo))
+ {
+ // Success!
+ pInit->sampleRate = streaminfo.sampleRate;
+ pInit->channels = streaminfo.channels;
+ pInit->bitsPerSample = streaminfo.bitsPerSample;
+ pInit->totalSampleCount = streaminfo.totalSampleCount;
+ pInit->maxBlockSize = streaminfo.maxBlockSize;
+
+ if (onMeta) {
+ drflac_metadata metadata;
+ metadata.type = DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO;
+ metadata.pRawData = NULL;
+ metadata.rawDataSize = 0;
+ metadata.data.streaminfo = streaminfo;
+ onMeta(pUserDataMD, &metadata);
+ }
+
+ pInit->runningFilePos += pageBodySize;
+ pInit->oggFirstBytePos = pInit->runningFilePos - 79; // Subtracting 79 will place us right on top of the "OggS" identifier of the FLAC bos page.
+ pInit->oggSerial = header.serialNumber;
+ pInit->oggBosHeader = header;
+ break;
+ }
+ else
+ {
+ // Failed to read STREAMINFO block. Aww, so close...
+ return DR_FALSE;
+ }
+ }
+ else
+ {
+ // Invalid file.
+ return DR_FALSE;
+ }
+ }
+ else
+ {
+ // Not a FLAC header. Skip it.
+ if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) {
+ return DR_FALSE;
+ }
+ }
+ }
+ else
+ {
+ // Not a FLAC header. Seek past the entire page and move on to the next.
+ if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) {
+ return DR_FALSE;
+ }
+ }
+ }
+ else
+ {
+ if (!onSeek(pUserData, pageBodySize, drflac_seek_origin_current)) {
+ return DR_FALSE;
+ }
+ }
+
+ pInit->runningFilePos += pageBodySize;
+
+
+ // Read the header of the next page.
+ if (!drflac_ogg__read_page_header(onRead, pUserData, &header, &headerSize)) {
+ return DR_FALSE;
+ }
+ pInit->runningFilePos += headerSize;
+ }
+
+
+ // If we get here it means we found a FLAC audio stream. We should be sitting on the first byte of the header of the next page. The next
+ // packets in the FLAC logical stream contain the metadata. The only thing left to do in the initialiation phase for Ogg is to create the
+ // Ogg bistream object.
+ pInit->hasMetadataBlocks = DR_TRUE; // <-- Always have at least VORBIS_COMMENT metadata block.
+ return DR_TRUE;
+}
+#endif
+
+drBool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD)
+{
+ if (pInit == NULL || onRead == NULL || onSeek == NULL) {
+ return DR_FALSE;
+ }
+
+ pInit->onRead = onRead;
+ pInit->onSeek = onSeek;
+ pInit->onMeta = onMeta;
+ pInit->pUserData = pUserData;
+ pInit->pUserDataMD = pUserDataMD;
+
+ uint8_t id[4];
+ if (onRead(pUserData, id, 4) != 4) {
+ return DR_FALSE;
+ }
+
+ if (id[0] == 'f' && id[1] == 'L' && id[2] == 'a' && id[3] == 'C') {
+ return drflac__init_private__native(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD);
+ }
+
+#ifndef DR_FLAC_NO_OGG
+ if (id[0] == 'O' && id[1] == 'g' && id[2] == 'g' && id[3] == 'S') {
+ return drflac__init_private__ogg(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD);
+ }
+#endif
+
+ // Unsupported container.
+ return DR_FALSE;
+}
+
+void drflac__init_from_info(drflac* pFlac, drflac_init_info* pInit)
+{
+ assert(pFlac != NULL);
+ assert(pInit != NULL);
+
+ memset(pFlac, 0, sizeof(*pFlac));
+ pFlac->bs.onRead = pInit->onRead;
+ pFlac->bs.onSeek = pInit->onSeek;
+ pFlac->bs.pUserData = pInit->pUserData;
+ pFlac->bs.nextL2Line = sizeof(pFlac->bs.cacheL2) / sizeof(pFlac->bs.cacheL2[0]); // <-- Initialize to this to force a client-side data retrieval right from the start.
+ pFlac->bs.consumedBits = sizeof(pFlac->bs.cache)*8;
+
+ pFlac->onMeta = pInit->onMeta;
+ pFlac->pUserDataMD = pInit->pUserDataMD;
+ pFlac->maxBlockSize = pInit->maxBlockSize;
+ pFlac->sampleRate = pInit->sampleRate;
+ pFlac->channels = (uint8_t)pInit->channels;
+ pFlac->bitsPerSample = (uint8_t)pInit->bitsPerSample;
+ pFlac->totalSampleCount = pInit->totalSampleCount;
+ pFlac->container = pInit->container;
+}
+
+drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD)
+{
+ drflac_init_info init;
+ if (!drflac__init_private(&init, onRead, onSeek, onMeta, pUserData, pUserDataMD)) {
+ return NULL;
+ }
+
+ size_t allocationSize = sizeof(drflac);
+ allocationSize += init.maxBlockSize * init.channels * sizeof(int32_t);
+ //allocationSize += init.seektableSize;
+
+
+#ifndef DR_FLAC_NO_OGG
+ // There's additional data required for Ogg streams.
+ if (init.container == drflac_container_ogg) {
+ allocationSize += sizeof(drflac_oggbs);
+ }
+#endif
+
+ drflac* pFlac = (drflac*)malloc(allocationSize);
+ drflac__init_from_info(pFlac, &init);
+ pFlac->pDecodedSamples = (int32_t*)pFlac->pExtraData;
+
+#ifndef DR_FLAC_NO_OGG
+ if (init.container == drflac_container_ogg) {
+ drflac_oggbs* oggbs = (drflac_oggbs*)(((int32_t*)pFlac->pExtraData) + init.maxBlockSize*init.channels);
+ oggbs->onRead = onRead;
+ oggbs->onSeek = onSeek;
+ oggbs->pUserData = pUserData;
+ oggbs->currentBytePos = init.oggFirstBytePos;
+ oggbs->firstBytePos = init.oggFirstBytePos;
+ oggbs->serialNumber = init.oggSerial;
+ oggbs->bosPageHeader = init.oggBosHeader;
+ oggbs->bytesRemainingInPage = 0;
+
+ // The Ogg bistream needs to be layered on top of the original bitstream.
+ pFlac->bs.onRead = drflac__on_read_ogg;
+ pFlac->bs.onSeek = drflac__on_seek_ogg;
+ pFlac->bs.pUserData = (void*)oggbs;
+ }
+#endif
+
+ // Decode metadata before returning.
+ if (init.hasMetadataBlocks) {
+ if (!drflac__read_and_decode_metadata(pFlac)) {
+ free(pFlac);
+ return NULL;
+ }
+ }
+
+ return pFlac;
+}
+
+
+
+#ifndef DR_FLAC_NO_STDIO
+typedef void* drflac_file;
+
+#if defined(DR_FLAC_NO_WIN32_IO) || !defined(_WIN32)
+#include <stdio.h>
+
+static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead)
+{
+ return fread(bufferOut, 1, bytesToRead, (FILE*)pUserData);
+}
+
+static drBool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin)
+{
+ assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start));
+
+ return fseek((FILE*)pUserData, offset, (origin == drflac_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
+}
+
+static drflac_file drflac__open_file_handle(const char* filename)
+{
+ FILE* pFile;
+#ifdef _MSC_VER
+ if (fopen_s(&pFile, filename, "rb") != 0) {
+ return NULL;
+ }
+#else
+ pFile = fopen(filename, "rb");
+ if (pFile == NULL) {
+ return NULL;
+ }
+#endif
+
+ return (drflac_file)pFile;
+}
+
+static void drflac__close_file_handle(drflac_file file)
+{
+ fclose((FILE*)file);
+}
+#else
+#include <windows.h>
+
+static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead)
+{
+ assert(bytesToRead < 0xFFFFFFFF); // dr_flac will never request huge amounts of data at a time. This is a safe assertion.
+
+ DWORD bytesRead;
+ ReadFile((HANDLE)pUserData, bufferOut, (DWORD)bytesToRead, &bytesRead, NULL);
+
+ return (size_t)bytesRead;
+}
+
+static drBool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin)
+{
+ assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start));
+
+ return SetFilePointer((HANDLE)pUserData, offset, NULL, (origin == drflac_seek_origin_current) ? FILE_CURRENT : FILE_BEGIN) != INVALID_SET_FILE_POINTER;
+}
+
+static drflac_file drflac__open_file_handle(const char* filename)
+{
+ HANDLE hFile = CreateFileA(filename, FILE_GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFile == INVALID_HANDLE_VALUE) {
+ return NULL;
+ }
+
+ return (drflac_file)hFile;
+}
+
+static void drflac__close_file_handle(drflac_file file)
+{
+ CloseHandle((HANDLE)file);
+}
+#endif
+
+
+drflac* drflac_open_file(const char* filename)
+{
+ drflac_file file = drflac__open_file_handle(filename);
+ if (file == NULL) {
+ return NULL;
+ }
+
+ drflac* pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)file);
+ if (pFlac == NULL) {
+ drflac__close_file_handle(file);
+ return NULL;
+ }
+
+ return pFlac;
+}
+
+drflac* drflac_open_file_with_metadata(const char* filename, drflac_meta_proc onMeta, void* pUserData)
+{
+ drflac_file file = drflac__open_file_handle(filename);
+ if (file == NULL) {
+ return NULL;
+ }
+
+ drflac* pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, (void*)file, pUserData);
+ if (pFlac == NULL) {
+ drflac__close_file_handle(file);
+ return pFlac;
+ }
+
+ return pFlac;
+}
+#endif //DR_FLAC_NO_STDIO
+
+static size_t drflac__on_read_memory(void* pUserData, void* bufferOut, size_t bytesToRead)
+{
+ drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData;
+ assert(memoryStream != NULL);
+ assert(memoryStream->dataSize >= memoryStream->currentReadPos);
+
+ size_t bytesRemaining = memoryStream->dataSize - memoryStream->currentReadPos;
+ if (bytesToRead > bytesRemaining) {
+ bytesToRead = bytesRemaining;
+ }
+
+ if (bytesToRead > 0) {
+ memcpy(bufferOut, memoryStream->data + memoryStream->currentReadPos, bytesToRead);
+ memoryStream->currentReadPos += bytesToRead;
+ }
+
+ return bytesToRead;
+}
+
+static drBool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_seek_origin origin)
+{
+ drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData;
+ assert(memoryStream != NULL);
+ assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start));
+
+ if (origin == drflac_seek_origin_current) {
+ if (memoryStream->currentReadPos + offset <= memoryStream->dataSize) {
+ memoryStream->currentReadPos += offset;
+ } else {
+ memoryStream->currentReadPos = memoryStream->dataSize; // Trying to seek too far forward.
+ }
+ } else {
+ if ((uint32_t)offset <= memoryStream->dataSize) {
+ memoryStream->currentReadPos = offset;
+ } else {
+ memoryStream->currentReadPos = memoryStream->dataSize; // Trying to seek too far forward.
+ }
+ }
+
+ return DR_TRUE;
+}
+
+drflac* drflac_open_memory(const void* data, size_t dataSize)
+{
+ drflac__memory_stream memoryStream;
+ memoryStream.data = (const unsigned char*)data;
+ memoryStream.dataSize = dataSize;
+ memoryStream.currentReadPos = 0;
+ drflac* pFlac = drflac_open(drflac__on_read_memory, drflac__on_seek_memory, &memoryStream);
+ if (pFlac == NULL) {
+ return NULL;
+ }
+
+ pFlac->memoryStream = memoryStream;
+
+ // This is an awful hack...
+#ifndef DR_FLAC_NO_OGG
+ if (pFlac->container == drflac_container_ogg)
+ {
+ drflac_oggbs* oggbs = (drflac_oggbs*)(((int32_t*)pFlac->pExtraData) + pFlac->maxBlockSize*pFlac->channels);
+ oggbs->pUserData = &pFlac->memoryStream;
+ }
+ else
+#endif
+ {
+ pFlac->bs.pUserData = &pFlac->memoryStream;
+ }
+
+ return pFlac;
+}
+
+drflac* drflac_open_memory_with_metadata(const void* data, size_t dataSize, drflac_meta_proc onMeta, void* pUserData)
+{
+ drflac__memory_stream memoryStream;
+ memoryStream.data = (const unsigned char*)data;
+ memoryStream.dataSize = dataSize;
+ memoryStream.currentReadPos = 0;
+ drflac* pFlac = drflac_open_with_metadata_private(drflac__on_read_memory, drflac__on_seek_memory, onMeta, &memoryStream, pUserData);
+ if (pFlac == NULL) {
+ return NULL;
+ }
+
+ pFlac->memoryStream = memoryStream;
+
+ // This is an awful hack...
+#ifndef DR_FLAC_NO_OGG
+ if (pFlac->container == drflac_container_ogg)
+ {
+ drflac_oggbs* oggbs = (drflac_oggbs*)(((int32_t*)pFlac->pExtraData) + pFlac->maxBlockSize*pFlac->channels);
+ oggbs->pUserData = &pFlac->memoryStream;
+ }
+ else
+#endif
+ {
+ pFlac->bs.pUserData = &pFlac->memoryStream;
+ }
+
+ return pFlac;
+}
+
+
+
+drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData)
+{
+ return drflac_open_with_metadata_private(onRead, onSeek, NULL, pUserData, pUserData);
+}
+
+drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData)
+{
+ return drflac_open_with_metadata_private(onRead, onSeek, onMeta, pUserData, pUserData);
+}
+
+void drflac_close(drflac* pFlac)
+{
+ if (pFlac == NULL) {
+ return;
+ }
+
+#ifndef DR_FLAC_NO_STDIO
+ // If we opened the file with drflac_open_file() we will want to close the file handle. We can know whether or not drflac_open_file()
+ // was used by looking at the callbacks.
+ if (pFlac->bs.onRead == drflac__on_read_stdio) {
+ drflac__close_file_handle((drflac_file)pFlac->bs.pUserData);
+ }
+
+#ifndef DR_FLAC_NO_OGG
+ // Need to clean up Ogg streams a bit differently due to the way the bit streaming is chained.
+ if (pFlac->container == drflac_container_ogg) {
+ assert(pFlac->bs.onRead == drflac__on_read_ogg);
+ drflac_oggbs* oggbs = (drflac_oggbs*)((int32_t*)pFlac->pExtraData + pFlac->maxBlockSize*pFlac->channels);
+ if (oggbs->onRead == drflac__on_read_stdio) {
+ drflac__close_file_handle((drflac_file)oggbs->pUserData);
+ }
+ }
+#endif
+#endif
+
+ free(pFlac);
+}
+
+uint64_t drflac__read_s32__misaligned(drflac* pFlac, uint64_t samplesToRead, int32_t* bufferOut)
+{
+ unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment);
+
+ // We should never be calling this when the number of samples to read is >= the sample count.
+ assert(samplesToRead < channelCount);
+ assert(pFlac->currentFrame.samplesRemaining > 0 && samplesToRead <= pFlac->currentFrame.samplesRemaining);
+
+
+ uint64_t samplesRead = 0;
+ while (samplesToRead > 0)
+ {
+ uint64_t totalSamplesInFrame = pFlac->currentFrame.header.blockSize * channelCount;
+ uint64_t samplesReadFromFrameSoFar = totalSamplesInFrame - pFlac->currentFrame.samplesRemaining;
+ unsigned int channelIndex = samplesReadFromFrameSoFar % channelCount;
+
+ uint64_t nextSampleInFrame = samplesReadFromFrameSoFar / channelCount;
+
+ int decodedSample = 0;
+ switch (pFlac->currentFrame.header.channelAssignment)
+ {
+ case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE:
+ {
+ if (channelIndex == 0) {
+ decodedSample = pFlac->currentFrame.subframes[channelIndex].pDecodedSamples[nextSampleInFrame];
+ } else {
+ int side = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame];
+ int left = pFlac->currentFrame.subframes[channelIndex - 1].pDecodedSamples[nextSampleInFrame];
+ decodedSample = left - side;
+ }
+
+ } break;
+
+ case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+ {
+ if (channelIndex == 0) {
+ int side = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame];
+ int right = pFlac->currentFrame.subframes[channelIndex + 1].pDecodedSamples[nextSampleInFrame];
+ decodedSample = side + right;
+ } else {
+ decodedSample = pFlac->currentFrame.subframes[channelIndex].pDecodedSamples[nextSampleInFrame];
+ }
+
+ } break;
+
+ case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE:
+ {
+ int mid;
+ int side;
+ if (channelIndex == 0) {
+ mid = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame];
+ side = pFlac->currentFrame.subframes[channelIndex + 1].pDecodedSamples[nextSampleInFrame];
+
+ mid = (((unsigned int)mid) << 1) | (side & 0x01);
+ decodedSample = (mid + side) >> 1;
+ } else {
+ mid = pFlac->currentFrame.subframes[channelIndex - 1].pDecodedSamples[nextSampleInFrame];
+ side = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame];
+
+ mid = (((unsigned int)mid) << 1) | (side & 0x01);
+ decodedSample = (mid - side) >> 1;
+ }
+
+ } break;
+
+ case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT:
+ default:
+ {
+ decodedSample = pFlac->currentFrame.subframes[channelIndex].pDecodedSamples[nextSampleInFrame];
+ } break;
+ }
+
+
+ decodedSample <<= ((32 - pFlac->bitsPerSample) + pFlac->currentFrame.subframes[channelIndex].wastedBitsPerSample);
+
+ if (bufferOut) {
+ *bufferOut++ = decodedSample;
+ }
+
+ samplesRead += 1;
+ pFlac->currentFrame.samplesRemaining -= 1;
+ samplesToRead -= 1;
+ }
+
+ return samplesRead;
+}
+
+uint64_t drflac__seek_forward_by_samples(drflac* pFlac, uint64_t samplesToRead)
+{
+ uint64_t samplesRead = 0;
+ while (samplesToRead > 0)
+ {
+ if (pFlac->currentFrame.samplesRemaining == 0)
+ {
+ if (!drflac__read_and_decode_next_frame(pFlac)) {
+ break; // Couldn't read the next frame, so just break from the loop and return.
+ }
+ }
+ else
+ {
+ samplesRead += 1;
+ pFlac->currentFrame.samplesRemaining -= 1;
+ samplesToRead -= 1;
+ }
+ }
+
+ return samplesRead;
+}
+
+uint64_t drflac_read_s32(drflac* pFlac, uint64_t samplesToRead, int32_t* bufferOut)
+{
+ // Note that <bufferOut> is allowed to be null, in which case this will be treated as something like a seek.
+ if (pFlac == NULL || samplesToRead == 0) {
+ return 0;
+ }
+
+ if (bufferOut == NULL) {
+ return drflac__seek_forward_by_samples(pFlac, samplesToRead);
+ }
+
+
+ uint64_t samplesRead = 0;
+ while (samplesToRead > 0)
+ {
+ // If we've run out of samples in this frame, go to the next.
+ if (pFlac->currentFrame.samplesRemaining == 0)
+ {
+ if (!drflac__read_and_decode_next_frame(pFlac)) {
+ break; // Couldn't read the next frame, so just break from the loop and return.
+ }
+ }
+ else
+ {
+ // Here is where we grab the samples and interleave them.
+
+ unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment);
+ uint64_t totalSamplesInFrame = pFlac->currentFrame.header.blockSize * channelCount;
+ uint64_t samplesReadFromFrameSoFar = totalSamplesInFrame - pFlac->currentFrame.samplesRemaining;
+
+ int misalignedSampleCount = samplesReadFromFrameSoFar % channelCount;
+ if (misalignedSampleCount > 0) {
+ uint64_t misalignedSamplesRead = drflac__read_s32__misaligned(pFlac, misalignedSampleCount, bufferOut);
+ samplesRead += misalignedSamplesRead;
+ samplesReadFromFrameSoFar += misalignedSamplesRead;
+ bufferOut += misalignedSamplesRead;
+ samplesToRead -= misalignedSamplesRead;
+ }
+
+
+ uint64_t alignedSampleCountPerChannel = samplesToRead / channelCount;
+ if (alignedSampleCountPerChannel > pFlac->currentFrame.samplesRemaining / channelCount) {
+ alignedSampleCountPerChannel = pFlac->currentFrame.samplesRemaining / channelCount;
+ }
+
+ uint64_t firstAlignedSampleInFrame = samplesReadFromFrameSoFar / channelCount;
+ unsigned int unusedBitsPerSample = 32 - pFlac->bitsPerSample;
+
+ switch (pFlac->currentFrame.header.channelAssignment)
+ {
+ case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE:
+ {
+ const int* pDecodedSamples0 = pFlac->currentFrame.subframes[0].pDecodedSamples + firstAlignedSampleInFrame;
+ const int* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame;
+
+ for (uint64_t i = 0; i < alignedSampleCountPerChannel; ++i) {
+ int left = pDecodedSamples0[i];
+ int side = pDecodedSamples1[i];
+ int right = left - side;
+
+ bufferOut[i*2+0] = left << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample);
+ bufferOut[i*2+1] = right << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample);
+ }
+ } break;
+
+ case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+ {
+ const int* pDecodedSamples0 = pFlac->currentFrame.subframes[0].pDecodedSamples + firstAlignedSampleInFrame;
+ const int* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame;
+
+ for (uint64_t i = 0; i < alignedSampleCountPerChannel; ++i) {
+ int side = pDecodedSamples0[i];
+ int right = pDecodedSamples1[i];
+ int left = right + side;
+
+ bufferOut[i*2+0] = left << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample);
+ bufferOut[i*2+1] = right << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample);
+ }
+ } break;
+
+ case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE:
+ {
+ const int* pDecodedSamples0 = pFlac->currentFrame.subframes[0].pDecodedSamples + firstAlignedSampleInFrame;
+ const int* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame;
+
+ for (uint64_t i = 0; i < alignedSampleCountPerChannel; ++i) {
+ int side = pDecodedSamples1[i];
+ int mid = (((uint32_t)pDecodedSamples0[i]) << 1) | (side & 0x01);
+
+ bufferOut[i*2+0] = ((mid + side) >> 1) << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample);
+ bufferOut[i*2+1] = ((mid - side) >> 1) << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample);
+ }
+ } break;
+
+ case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT:
+ default:
+ {
+ if (pFlac->currentFrame.header.channelAssignment == 1) // 1 = Stereo
+ {
+ // Stereo optimized inner loop unroll.
+ const int* pDecodedSamples0 = pFlac->currentFrame.subframes[0].pDecodedSamples + firstAlignedSampleInFrame;
+ const int* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame;
+
+ for (uint64_t i = 0; i < alignedSampleCountPerChannel; ++i) {
+ bufferOut[i*2+0] = pDecodedSamples0[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample);
+ bufferOut[i*2+1] = pDecodedSamples1[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample);
+ }
+ }
+ else
+ {
+ // Generic interleaving.
+ for (uint64_t i = 0; i < alignedSampleCountPerChannel; ++i) {
+ for (unsigned int j = 0; j < channelCount; ++j) {
+ bufferOut[(i*channelCount)+j] = (pFlac->currentFrame.subframes[j].pDecodedSamples[firstAlignedSampleInFrame + i]) << (unusedBitsPerSample + pFlac->currentFrame.subframes[j].wastedBitsPerSample);
+ }
+ }
+ }
+ } break;
+ }
+
+ uint64_t alignedSamplesRead = alignedSampleCountPerChannel * channelCount;
+ samplesRead += alignedSamplesRead;
+ samplesReadFromFrameSoFar += alignedSamplesRead;
+ bufferOut += alignedSamplesRead;
+ samplesToRead -= alignedSamplesRead;
+ pFlac->currentFrame.samplesRemaining -= (unsigned int)alignedSamplesRead;
+
+
+
+ // At this point we may still have some excess samples left to read.
+ if (samplesToRead > 0 && pFlac->currentFrame.samplesRemaining > 0)
+ {
+ uint64_t excessSamplesRead = 0;
+ if (samplesToRead < pFlac->currentFrame.samplesRemaining) {
+ excessSamplesRead = drflac__read_s32__misaligned(pFlac, samplesToRead, bufferOut);
+ } else {
+ excessSamplesRead = drflac__read_s32__misaligned(pFlac, pFlac->currentFrame.samplesRemaining, bufferOut);
+ }
+
+ samplesRead += excessSamplesRead;
+ samplesReadFromFrameSoFar += excessSamplesRead;
+ bufferOut += excessSamplesRead;
+ samplesToRead -= excessSamplesRead;
+ }
+ }
+ }
+
+ return samplesRead;
+}
+
+drBool32 drflac_seek_to_sample(drflac* pFlac, uint64_t sampleIndex)
+{
+ if (pFlac == NULL) {
+ return DR_FALSE;
+ }
+
+ if (sampleIndex == 0) {
+ return drflac__seek_to_first_frame(pFlac);
+ }
+
+ // Clamp the sample to the end.
+ if (sampleIndex >= pFlac->totalSampleCount) {
+ sampleIndex = pFlac->totalSampleCount - 1;
+ }
+
+
+ // Different techniques depending on encapsulation. Using the native FLAC seektable with Ogg encapsulation is a bit awkward so
+ // we'll instead use Ogg's natural seeking facility.
+#ifndef DR_FLAC_NO_OGG
+ if (pFlac->container == drflac_container_ogg)
+ {
+ return drflac_ogg__seek_to_sample(pFlac, sampleIndex);
+ }
+ else
+#endif
+ {
+ // First try seeking via the seek table. If this fails, fall back to a brute force seek which is much slower.
+ if (!drflac__seek_to_sample__seek_table(pFlac, sampleIndex)) {
+ return drflac__seek_to_sample__brute_force(pFlac, sampleIndex);
+ }
+ }
+
+
+ return DR_TRUE;
+}
+
+
+
+//// High Level APIs ////
+
+int32_t* drflac__full_decode_and_close(drflac* pFlac, unsigned int* channelsOut, unsigned int* sampleRateOut, uint64_t* totalSampleCountOut)
+{
+ assert(pFlac != NULL);
+
+ int32_t* pSampleData = NULL;
+ uint64_t totalSampleCount = pFlac->totalSampleCount;
+
+ if (totalSampleCount == 0)
+ {
+ int32_t buffer[4096];
+
+ size_t sampleDataBufferSize = sizeof(buffer);
+ pSampleData = (int32_t*)malloc(sampleDataBufferSize);
+ if (pSampleData == NULL) {
+ goto on_error;
+ }
+
+ uint64_t samplesRead;
+ while ((samplesRead = (uint64_t)drflac_read_s32(pFlac, sizeof(buffer)/sizeof(buffer[0]), buffer)) > 0)
+ {
+ if (((totalSampleCount + samplesRead) * sizeof(int32_t)) > sampleDataBufferSize) {
+ sampleDataBufferSize *= 2;
+ int32_t* pNewSampleData = (int32_t*)realloc(pSampleData, sampleDataBufferSize);
+ if (pNewSampleData == NULL) {
+ free(pSampleData);
+ goto on_error;
+ }
+
+ pSampleData = pNewSampleData;
+ }
+
+ memcpy(pSampleData + totalSampleCount, buffer, (size_t)(samplesRead*sizeof(int32_t)));
+ totalSampleCount += samplesRead;
+ }
+
+ // At this point everything should be decoded, but we just want to fill the unused part buffer with silence - need to
+ // protect those ears from random noise!
+ memset(pSampleData + totalSampleCount, 0, (size_t)(sampleDataBufferSize - totalSampleCount*sizeof(int32_t)));
+ }
+ else
+ {
+ uint64_t dataSize = totalSampleCount * sizeof(int32_t);
+ if (dataSize > SIZE_MAX) {
+ goto on_error; // The decoded data is too big.
+ }
+
+ pSampleData = (int32_t*)malloc((size_t)dataSize); // <-- Safe cast as per the check above.
+ if (pSampleData == NULL) {
+ goto on_error;
+ }
+
+ uint64_t samplesDecoded = drflac_read_s32(pFlac, pFlac->totalSampleCount, pSampleData);
+ if (samplesDecoded != pFlac->totalSampleCount) {
+ free(pSampleData);
+ goto on_error; // Something went wrong when decoding the FLAC stream.
+ }
+ }
+
+
+ if (sampleRateOut) *sampleRateOut = pFlac->sampleRate;
+ if (channelsOut) *channelsOut = pFlac->channels;
+ if (totalSampleCountOut) *totalSampleCountOut = totalSampleCount;
+
+ drflac_close(pFlac);
+ return pSampleData;
+
+on_error:
+ drflac_close(pFlac);
+ return NULL;
+}
+
+int32_t* drflac_open_and_decode_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount)
+{
+ // Safety.
+ if (sampleRate) *sampleRate = 0;
+ if (channels) *channels = 0;
+ if (totalSampleCount) *totalSampleCount = 0;
+
+ drflac* pFlac = drflac_open(onRead, onSeek, pUserData);
+ if (pFlac == NULL) {
+ return NULL;
+ }
+
+ return drflac__full_decode_and_close(pFlac, channels, sampleRate, totalSampleCount);
+}
+
+#ifndef DR_FLAC_NO_STDIO
+int32_t* drflac_open_and_decode_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount)
+{
+ if (sampleRate) *sampleRate = 0;
+ if (channels) *channels = 0;
+ if (totalSampleCount) *totalSampleCount = 0;
+
+ drflac* pFlac = drflac_open_file(filename);
+ if (pFlac == NULL) {
+ return NULL;
+ }
+
+ return drflac__full_decode_and_close(pFlac, channels, sampleRate, totalSampleCount);
+}
+#endif
+
+int32_t* drflac_open_and_decode_memory_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount)
+{
+ if (sampleRate) *sampleRate = 0;
+ if (channels) *channels = 0;
+ if (totalSampleCount) *totalSampleCount = 0;
+
+ drflac* pFlac = drflac_open_memory(data, dataSize);
+ if (pFlac == NULL) {
+ return NULL;
+ }
+
+ return drflac__full_decode_and_close(pFlac, channels, sampleRate, totalSampleCount);
+}
+
+void drflac_free(void* pSampleDataReturnedByOpenAndDecode)
+{
+ free(pSampleDataReturnedByOpenAndDecode);
+}
+
+
+
+
+void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, uint32_t commentCount, const char* pComments)
+{
+ if (pIter == NULL) {
+ return;
+ }
+
+ pIter->countRemaining = commentCount;
+ pIter->pRunningData = pComments;
+}
+
+const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, uint32_t* pCommentLengthOut)
+{
+ // Safety.
+ if (pCommentLengthOut) *pCommentLengthOut = 0;
+
+ if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) {
+ return NULL;
+ }
+
+ uint32_t length = drflac__le2host_32(*(uint32_t*)pIter->pRunningData);
+ pIter->pRunningData += 4;
+
+ const char* pComment = pIter->pRunningData;
+ pIter->pRunningData += length;
+ pIter->countRemaining -= 1;
+
+ if (pCommentLengthOut) *pCommentLengthOut = length;
+ return pComment;
+}
+#endif //DR_FLAC_IMPLEMENTATION
+
+
+// REVISION HISTORY
+//
+// v0.4 - 2016-09-29
+// - API/ABI CHANGE: Use fixed size 32-bit booleans instead of the built-in bool type.
+// - API CHANGE: Rename drflac_open_and_decode*() to drflac_open_and_decode*_s32()
+// - API CHANGE: Swap the order of "channels" and "sampleRate" parameters in drflac_open_and_decode*(). Rationale for this is to
+// keep it consistent with dr_audio.
+//
+// v0.3f - 2016-09-21
+// - Fix a warning with GCC.
+//
+// v0.3e - 2016-09-18
+// - Fixed a bug where GCC 4.3+ was not getting properly identified.
+// - Fixed a few typos.
+// - Changed date formats to ISO 8601 (YYYY-MM-DD).
+//
+// v0.3d - 2016-06-11
+// - Minor clean up.
+//
+// v0.3c - 2016-05-28
+// - Fixed compilation error.
+//
+// v0.3b - 2016-05-16
+// - Fixed Linux/GCC build.
+// - Updated documentation.
+//
+// v0.3a - 2016-05-15
+// - Minor fixes to documentation.
+//
+// v0.3 - 2016-05-11
+// - Optimizations. Now at about parity with the reference implementation on 32-bit builds.
+// - Lots of clean up.
+//
+// v0.2b - 2016-05-10
+// - Bug fixes.
+//
+// v0.2a - 2016-05-10
+// - Made drflac_open_and_decode() more robust.
+// - Removed an unused debugging variable
+//
+// v0.2 - 2016-05-09
+// - Added support for Ogg encapsulation.
+// - API CHANGE. Have the onSeek callback take a third argument which specifies whether or not the seek
+// should be relative to the start or the current position. Also changes the seeking rules such that
+// seeking offsets will never be negative.
+// - Have drflac_open_and_decode() fail gracefully if the stream has an unknown total sample count.
+//
+// v0.1b - 2016-05-07
+// - Properly close the file handle in drflac_open_file() and family when the decoder fails to initialize.
+// - Removed a stale comment.
+//
+// v0.1a - 2016-05-05
+// - Minor formatting changes.
+// - Fixed a warning on the GCC build.
+//
+// v0.1 - 2016-05-03
+// - Initial versioned release.
+
+
+// TODO
+// - Add support for initializing the decoder without a header STREAMINFO block.
+// - Test CUESHEET metadata blocks.
+
+
+/*
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+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 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.
+
+For more information, please refer to <http://unlicense.org/>
+*/
diff --git a/src/external/jar_mod.h b/src/external/jar_mod.h
index c39db65a..bee9f6ee 100644
--- a/src/external/jar_mod.h
+++ b/src/external/jar_mod.h
@@ -59,7 +59,7 @@
// - Initialize the jar_mod_context_t buffer. Must be called before doing anything else.
// Return 1 if success. 0 in case of error.
// -------------------------------------------
-// mulong jar_mod_load_file(jar_mod_context_t * modctx, char* filename)
+// mulong jar_mod_load_file(jar_mod_context_t * modctx, const char* filename)
//
// - "Load" a MOD from file, context must already be initialized.
// Return size of file in bytes.
@@ -247,7 +247,7 @@ bool jar_mod_init(jar_mod_context_t * modctx);
bool jar_mod_setcfg(jar_mod_context_t * modctx, int samplerate, int bits, int stereo, int stereo_separation, int filter);
void jar_mod_fillbuffer(jar_mod_context_t * modctx, short * outbuffer, unsigned long nbsample, jar_mod_tracker_buffer_state * trkbuf);
void jar_mod_unload(jar_mod_context_t * modctx);
-mulong jar_mod_load_file(jar_mod_context_t * modctx, char* filename);
+mulong jar_mod_load_file(jar_mod_context_t * modctx, const char* filename);
mulong jar_mod_current_samples(jar_mod_context_t * modctx);
mulong jar_mod_max_samples(jar_mod_context_t * modctx);
void jar_mod_seek_start(jar_mod_context_t * ctx);
@@ -1516,7 +1516,7 @@ void jar_mod_unload( jar_mod_context_t * modctx)
-mulong jar_mod_load_file(jar_mod_context_t * modctx, char* filename)
+mulong jar_mod_load_file(jar_mod_context_t * modctx, const char* filename)
{
mulong fsize = 0;
if(modctx->modfile)
diff --git a/src/external/jar_xm.h b/src/external/jar_xm.h
index f9ddb511..7f0517df 100644
--- a/src/external/jar_xm.h
+++ b/src/external/jar_xm.h
@@ -102,7 +102,7 @@ int jar_xm_create_context_from_file(jar_xm_context_t** ctx, uint32_t rate, const
* @deprecated This function is unsafe!
* @see jar_xm_create_context_safe()
*/
-int jar_xm_create_context(jar_xm_context_t**, const char* moddata, uint32_t rate);
+int jar_xm_create_context(jar_xm_context_t** ctx, const char* moddata, uint32_t rate);
/** Create a XM context.
*
@@ -114,17 +114,17 @@ int jar_xm_create_context(jar_xm_context_t**, const char* moddata, uint32_t rate
* @returns 1 if module data is not sane
* @returns 2 if memory allocation failed
*/
-int jar_xm_create_context_safe(jar_xm_context_t**, const char* moddata, size_t moddata_length, uint32_t rate);
+int jar_xm_create_context_safe(jar_xm_context_t** ctx, const char* moddata, size_t moddata_length, uint32_t rate);
/** Free a XM context created by jar_xm_create_context(). */
-void jar_xm_free_context(jar_xm_context_t*);
+void jar_xm_free_context(jar_xm_context_t* ctx);
/** Play the module and put the sound samples in an output buffer.
*
* @param output buffer of 2*numsamples elements (A left and right value for each sample)
* @param numsamples number of samples to generate
*/
-void jar_xm_generate_samples(jar_xm_context_t*, float* output, size_t numsamples);
+void jar_xm_generate_samples(jar_xm_context_t* ctx, float* output, size_t numsamples);
/** Play the module, resample from 32 bit to 16 bit, and put the sound samples in an output buffer.
*
@@ -173,12 +173,12 @@ void jar_xm_generate_samples_8bit(jar_xm_context_t* ctx, char* output, size_t nu
*
* @param loopcnt maximum number of loops. Use 0 to loop
* indefinitely. */
-void jar_xm_set_max_loop_count(jar_xm_context_t*, uint8_t loopcnt);
+void jar_xm_set_max_loop_count(jar_xm_context_t* ctx, uint8_t loopcnt);
/** Get the loop count of the currently playing module. This value is
* 0 when the module is still playing, 1 when the module has looped
* once, etc. */
-uint8_t jar_xm_get_loop_count(jar_xm_context_t*);
+uint8_t jar_xm_get_loop_count(jar_xm_context_t* ctx);
@@ -188,7 +188,7 @@ uint8_t jar_xm_get_loop_count(jar_xm_context_t*);
*
* @return whether the channel was muted.
*/
-bool jar_xm_mute_channel(jar_xm_context_t*, uint16_t, bool);
+bool jar_xm_mute_channel(jar_xm_context_t* ctx, uint16_t, bool);
/** Mute or unmute an instrument.
*
@@ -197,43 +197,43 @@ bool jar_xm_mute_channel(jar_xm_context_t*, uint16_t, bool);
*
* @return whether the instrument was muted.
*/
-bool jar_xm_mute_instrument(jar_xm_context_t*, uint16_t, bool);
+bool jar_xm_mute_instrument(jar_xm_context_t* ctx, uint16_t, bool);
/** Get the module name as a NUL-terminated string. */
-const char* jar_xm_get_module_name(jar_xm_context_t*);
+const char* jar_xm_get_module_name(jar_xm_context_t* ctx);
/** Get the tracker name as a NUL-terminated string. */
-const char* jar_xm_get_tracker_name(jar_xm_context_t*);
+const char* jar_xm_get_tracker_name(jar_xm_context_t* ctx);
/** Get the number of channels. */
-uint16_t jar_xm_get_number_of_channels(jar_xm_context_t*);
+uint16_t jar_xm_get_number_of_channels(jar_xm_context_t* ctx);
/** Get the module length (in patterns). */
uint16_t jar_xm_get_module_length(jar_xm_context_t*);
/** Get the number of patterns. */
-uint16_t jar_xm_get_number_of_patterns(jar_xm_context_t*);
+uint16_t jar_xm_get_number_of_patterns(jar_xm_context_t* ctx);
/** Get the number of rows of a pattern.
*
* @note Pattern numbers go from 0 to
* jar_xm_get_number_of_patterns(...)-1.
*/
-uint16_t jar_xm_get_number_of_rows(jar_xm_context_t*, uint16_t);
+uint16_t jar_xm_get_number_of_rows(jar_xm_context_t* ctx, uint16_t);
/** Get the number of instruments. */
-uint16_t jar_xm_get_number_of_instruments(jar_xm_context_t*);
+uint16_t jar_xm_get_number_of_instruments(jar_xm_context_t* ctx);
/** Get the number of samples of an instrument.
*
* @note Instrument numbers go from 1 to
* jar_xm_get_number_of_instruments(...).
*/
-uint16_t jar_xm_get_number_of_samples(jar_xm_context_t*, uint16_t);
+uint16_t jar_xm_get_number_of_samples(jar_xm_context_t* ctx, uint16_t);
@@ -242,7 +242,7 @@ uint16_t jar_xm_get_number_of_samples(jar_xm_context_t*, uint16_t);
* @param bpm will receive the current BPM
* @param tempo will receive the current tempo (ticks per line)
*/
-void jar_xm_get_playing_speed(jar_xm_context_t*, uint16_t* bpm, uint16_t* tempo);
+void jar_xm_get_playing_speed(jar_xm_context_t* ctx, uint16_t* bpm, uint16_t* tempo);
/** Get the current position in the module being played.
*
@@ -257,7 +257,7 @@ void jar_xm_get_playing_speed(jar_xm_context_t*, uint16_t* bpm, uint16_t* tempo)
* generated samples (divide by sample rate to get seconds of
* generated audio)
*/
-void jar_xm_get_position(jar_xm_context_t*, uint8_t* pattern_index, uint8_t* pattern, uint8_t* row, uint64_t* samples);
+void jar_xm_get_position(jar_xm_context_t* ctx, uint8_t* pattern_index, uint8_t* pattern, uint8_t* row, uint64_t* samples);
/** Get the latest time (in number of generated samples) when a
* particular instrument was triggered in any channel.
@@ -265,7 +265,7 @@ void jar_xm_get_position(jar_xm_context_t*, uint8_t* pattern_index, uint8_t* pat
* @note Instrument numbers go from 1 to
* jar_xm_get_number_of_instruments(...).
*/
-uint64_t jar_xm_get_latest_trigger_of_instrument(jar_xm_context_t*, uint16_t);
+uint64_t jar_xm_get_latest_trigger_of_instrument(jar_xm_context_t* ctx, uint16_t);
/** Get the latest time (in number of generated samples) when a
* particular sample was triggered in any channel.
@@ -276,21 +276,21 @@ uint64_t jar_xm_get_latest_trigger_of_instrument(jar_xm_context_t*, uint16_t);
* @note Sample numbers go from 0 to
* jar_xm_get_nubmer_of_samples(...,instr)-1.
*/
-uint64_t jar_xm_get_latest_trigger_of_sample(jar_xm_context_t*, uint16_t instr, uint16_t sample);
+uint64_t jar_xm_get_latest_trigger_of_sample(jar_xm_context_t* ctx, uint16_t instr, uint16_t sample);
/** Get the latest time (in number of generated samples) when any
* instrument was triggered in a given channel.
*
* @note Channel numbers go from 1 to jar_xm_get_number_of_channels(...).
*/
-uint64_t jar_xm_get_latest_trigger_of_channel(jar_xm_context_t*, uint16_t);
+uint64_t jar_xm_get_latest_trigger_of_channel(jar_xm_context_t* ctx, uint16_t);
/** Get the number of remaining samples. Divide by 2 to get the number of individual LR data samples.
*
* @note This is the remaining number of samples before the loop starts module again, or halts if on last pass.
* @note This function is very slow and should only be run once, if at all.
*/
-uint64_t jar_xm_get_remaining_samples(jar_xm_context_t*);
+uint64_t jar_xm_get_remaining_samples(jar_xm_context_t* ctx);
#ifdef __cplusplus
}
@@ -308,7 +308,7 @@ uint64_t jar_xm_get_remaining_samples(jar_xm_context_t*);
#include <math.h>
#include <string.h>
-#if JAR_XM_DEBUG
+#ifdef JAR_XM_DEBUG
#include <stdio.h>
#define DEBUG(fmt, ...) do { \
fprintf(stderr, "%s(): " fmt "\n", __func__, __VA_ARGS__); \
@@ -638,7 +638,7 @@ int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, siz
/* Initialize most of the fields to 0, 0.f, NULL or false depending on type */
memset(mempool, 0, bytes_needed);
- ctx = (*ctxp = (jar_xm_context_t*)mempool);
+ ctx = (*ctxp = (jar_xm_context_t *)mempool);
ctx->allocated_memory = mempool; /* Keep original pointer for free() */
mempool += sizeof(jar_xm_context_t);
@@ -685,20 +685,18 @@ int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, siz
return 0;
}
-void jar_xm_free_context(jar_xm_context_t* context) {
- free(context->allocated_memory);
+void jar_xm_free_context(jar_xm_context_t* ctx) {
+ free(ctx->allocated_memory);
}
-void jar_xm_set_max_loop_count(jar_xm_context_t* context, uint8_t loopcnt) {
- context->max_loop_count = loopcnt;
+void jar_xm_set_max_loop_count(jar_xm_context_t* ctx, uint8_t loopcnt) {
+ ctx->max_loop_count = loopcnt;
}
-uint8_t jar_xm_get_loop_count(jar_xm_context_t* context) {
- return context->loop_count;
+uint8_t jar_xm_get_loop_count(jar_xm_context_t* ctx) {
+ return ctx->loop_count;
}
-
-
bool jar_xm_mute_channel(jar_xm_context_t* ctx, uint16_t channel, bool mute) {
bool old = ctx->channels[channel - 1].muted;
ctx->channels[channel - 1].muted = mute;
@@ -1435,7 +1433,7 @@ static void jar_xm_volume_slide(jar_xm_channel_context_t* ch, uint8_t rawval) {
}
}
-static float jar_xm_envelope_lerp(jar_xm_envelope_point_t* restrict a, jar_xm_envelope_point_t* restrict b, uint16_t pos) {
+static float jar_xm_envelope_lerp(jar_xm_envelope_point_t* a, jar_xm_envelope_point_t* b, uint16_t pos) {
/* Linear interpolation between two envelope points */
if(pos <= a->frame) return a->value;
else if(pos >= b->frame) return b->value;
diff --git a/src/external/lua/include/lauxlib.h b/src/external/lua/include/lauxlib.h
new file mode 100644
index 00000000..ddb7c228
--- /dev/null
+++ b/src/external/lua/include/lauxlib.h
@@ -0,0 +1,256 @@
+/*
+** $Id: lauxlib.h,v 1.129 2015/11/23 11:29:43 roberto Exp $
+** Auxiliary functions for building Lua libraries
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lauxlib_h
+#define lauxlib_h
+
+
+#include <stddef.h>
+#include <stdio.h>
+
+#include "lua.h"
+
+
+
+/* extra error code for 'luaL_load' */
+#define LUA_ERRFILE (LUA_ERRERR+1)
+
+
+typedef struct luaL_Reg {
+ const char *name;
+ lua_CFunction func;
+} luaL_Reg;
+
+
+#define LUAL_NUMSIZES (sizeof(lua_Integer)*16 + sizeof(lua_Number))
+
+LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz);
+#define luaL_checkversion(L) \
+ luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES)
+
+LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
+LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
+LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len);
+LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg);
+LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg,
+ size_t *l);
+LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg,
+ const char *def, size_t *l);
+LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg);
+LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def);
+
+LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg);
+LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg,
+ lua_Integer def);
+
+LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
+LUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t);
+LUALIB_API void (luaL_checkany) (lua_State *L, int arg);
+
+LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname);
+LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname);
+LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname);
+LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
+
+LUALIB_API void (luaL_where) (lua_State *L, int lvl);
+LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
+
+LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def,
+ const char *const lst[]);
+
+LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname);
+LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
+
+/* predefined references */
+#define LUA_NOREF (-2)
+#define LUA_REFNIL (-1)
+
+LUALIB_API int (luaL_ref) (lua_State *L, int t);
+LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
+
+LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename,
+ const char *mode);
+
+#define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL)
+
+LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz,
+ const char *name, const char *mode);
+LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
+
+LUALIB_API lua_State *(luaL_newstate) (void);
+
+LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx);
+
+LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
+ const char *r);
+
+LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup);
+
+LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname);
+
+LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1,
+ const char *msg, int level);
+
+LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
+ lua_CFunction openf, int glb);
+
+/*
+** ===============================================================
+** some useful macros
+** ===============================================================
+*/
+
+
+#define luaL_newlibtable(L,l) \
+ lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1)
+
+#define luaL_newlib(L,l) \
+ (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
+
+#define luaL_argcheck(L, cond,arg,extramsg) \
+ ((void)((cond) || luaL_argerror(L, (arg), (extramsg))))
+#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
+#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
+
+#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i)))
+
+#define luaL_dofile(L, fn) \
+ (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
+
+#define luaL_dostring(L, s) \
+ (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
+
+#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
+
+#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
+
+#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL)
+
+
+/*
+** {======================================================
+** Generic Buffer manipulation
+** =======================================================
+*/
+
+typedef struct luaL_Buffer {
+ char *b; /* buffer address */
+ size_t size; /* buffer size */
+ size_t n; /* number of characters in buffer */
+ lua_State *L;
+ char initb[LUAL_BUFFERSIZE]; /* initial buffer */
+} luaL_Buffer;
+
+
+#define luaL_addchar(B,c) \
+ ((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \
+ ((B)->b[(B)->n++] = (c)))
+
+#define luaL_addsize(B,s) ((B)->n += (s))
+
+LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
+LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz);
+LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
+LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);
+LUALIB_API void (luaL_addvalue) (luaL_Buffer *B);
+LUALIB_API void (luaL_pushresult) (luaL_Buffer *B);
+LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz);
+LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz);
+
+#define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE)
+
+/* }====================================================== */
+
+
+
+/*
+** {======================================================
+** File handles for IO library
+** =======================================================
+*/
+
+/*
+** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and
+** initial structure 'luaL_Stream' (it may contain other fields
+** after that initial structure).
+*/
+
+#define LUA_FILEHANDLE "FILE*"
+
+
+typedef struct luaL_Stream {
+ FILE *f; /* stream (NULL for incompletely created streams) */
+ lua_CFunction closef; /* to close stream (NULL for closed streams) */
+} luaL_Stream;
+
+/* }====================================================== */
+
+
+
+/* compatibility with old module system */
+#if defined(LUA_COMPAT_MODULE)
+
+LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname,
+ int sizehint);
+LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname,
+ const luaL_Reg *l, int nup);
+
+#define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0))
+
+#endif
+
+
+/*
+** {==================================================================
+** "Abstraction Layer" for basic report of messages and errors
+** ===================================================================
+*/
+
+/* print a string */
+#if !defined(lua_writestring)
+#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout)
+#endif
+
+/* print a newline and flush the output */
+#if !defined(lua_writeline)
+#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout))
+#endif
+
+/* print an error message */
+#if !defined(lua_writestringerror)
+#define lua_writestringerror(s,p) \
+ (fprintf(stderr, (s), (p)), fflush(stderr))
+#endif
+
+/* }================================================================== */
+
+
+/*
+** {============================================================
+** Compatibility with deprecated conversions
+** =============================================================
+*/
+#if defined(LUA_COMPAT_APIINTCASTS)
+
+#define luaL_checkunsigned(L,a) ((lua_Unsigned)luaL_checkinteger(L,a))
+#define luaL_optunsigned(L,a,d) \
+ ((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(d)))
+
+#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
+#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d)))
+
+#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n)))
+#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d)))
+
+#endif
+/* }============================================================ */
+
+
+
+#endif
+
+
diff --git a/src/external/lua/include/lua.h b/src/external/lua/include/lua.h
new file mode 100644
index 00000000..f78899fc
--- /dev/null
+++ b/src/external/lua/include/lua.h
@@ -0,0 +1,486 @@
+/*
+** $Id: lua.h,v 1.331 2016/05/30 15:53:28 roberto Exp $
+** Lua - A Scripting Language
+** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
+** See Copyright Notice at the end of this file
+*/
+
+
+#ifndef lua_h
+#define lua_h
+
+#include <stdarg.h>
+#include <stddef.h>
+
+
+#include "luaconf.h"
+
+
+#define LUA_VERSION_MAJOR "5"
+#define LUA_VERSION_MINOR "3"
+#define LUA_VERSION_NUM 503
+#define LUA_VERSION_RELEASE "3"
+
+#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
+#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
+#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2016 Lua.org, PUC-Rio"
+#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
+
+
+/* mark for precompiled code ('<esc>Lua') */
+#define LUA_SIGNATURE "\x1bLua"
+
+/* option for multiple returns in 'lua_pcall' and 'lua_call' */
+#define LUA_MULTRET (-1)
+
+
+/*
+** Pseudo-indices
+** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty
+** space after that to help overflow detection)
+*/
+#define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000)
+#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i))
+
+
+/* thread status */
+#define LUA_OK 0
+#define LUA_YIELD 1
+#define LUA_ERRRUN 2
+#define LUA_ERRSYNTAX 3
+#define LUA_ERRMEM 4
+#define LUA_ERRGCMM 5
+#define LUA_ERRERR 6
+
+
+typedef struct lua_State lua_State;
+
+
+/*
+** basic types
+*/
+#define LUA_TNONE (-1)
+
+#define LUA_TNIL 0
+#define LUA_TBOOLEAN 1
+#define LUA_TLIGHTUSERDATA 2
+#define LUA_TNUMBER 3
+#define LUA_TSTRING 4
+#define LUA_TTABLE 5
+#define LUA_TFUNCTION 6
+#define LUA_TUSERDATA 7
+#define LUA_TTHREAD 8
+
+#define LUA_NUMTAGS 9
+
+
+
+/* minimum Lua stack available to a C function */
+#define LUA_MINSTACK 20
+
+
+/* predefined values in the registry */
+#define LUA_RIDX_MAINTHREAD 1
+#define LUA_RIDX_GLOBALS 2
+#define LUA_RIDX_LAST LUA_RIDX_GLOBALS
+
+
+/* type of numbers in Lua */
+typedef LUA_NUMBER lua_Number;
+
+
+/* type for integer functions */
+typedef LUA_INTEGER lua_Integer;
+
+/* unsigned integer type */
+typedef LUA_UNSIGNED lua_Unsigned;
+
+/* type for continuation-function contexts */
+typedef LUA_KCONTEXT lua_KContext;
+
+
+/*
+** Type for C functions registered with Lua
+*/
+typedef int (*lua_CFunction) (lua_State *L);
+
+/*
+** Type for continuation functions
+*/
+typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx);
+
+
+/*
+** Type for functions that read/write blocks when loading/dumping Lua chunks
+*/
+typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz);
+
+typedef int (*lua_Writer) (lua_State *L, const void *p, size_t sz, void *ud);
+
+
+/*
+** Type for memory-allocation functions
+*/
+typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
+
+
+
+/*
+** generic extra include file
+*/
+#if defined(LUA_USER_H)
+#include LUA_USER_H
+#endif
+
+
+/*
+** RCS ident string
+*/
+extern const char lua_ident[];
+
+
+/*
+** state manipulation
+*/
+LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
+LUA_API void (lua_close) (lua_State *L);
+LUA_API lua_State *(lua_newthread) (lua_State *L);
+
+LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
+
+
+LUA_API const lua_Number *(lua_version) (lua_State *L);
+
+
+/*
+** basic stack manipulation
+*/
+LUA_API int (lua_absindex) (lua_State *L, int idx);
+LUA_API int (lua_gettop) (lua_State *L);
+LUA_API void (lua_settop) (lua_State *L, int idx);
+LUA_API void (lua_pushvalue) (lua_State *L, int idx);
+LUA_API void (lua_rotate) (lua_State *L, int idx, int n);
+LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx);
+LUA_API int (lua_checkstack) (lua_State *L, int n);
+
+LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n);
+
+
+/*
+** access functions (stack -> C)
+*/
+
+LUA_API int (lua_isnumber) (lua_State *L, int idx);
+LUA_API int (lua_isstring) (lua_State *L, int idx);
+LUA_API int (lua_iscfunction) (lua_State *L, int idx);
+LUA_API int (lua_isinteger) (lua_State *L, int idx);
+LUA_API int (lua_isuserdata) (lua_State *L, int idx);
+LUA_API int (lua_type) (lua_State *L, int idx);
+LUA_API const char *(lua_typename) (lua_State *L, int tp);
+
+LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum);
+LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum);
+LUA_API int (lua_toboolean) (lua_State *L, int idx);
+LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len);
+LUA_API size_t (lua_rawlen) (lua_State *L, int idx);
+LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx);
+LUA_API void *(lua_touserdata) (lua_State *L, int idx);
+LUA_API lua_State *(lua_tothread) (lua_State *L, int idx);
+LUA_API const void *(lua_topointer) (lua_State *L, int idx);
+
+
+/*
+** Comparison and arithmetic functions
+*/
+
+#define LUA_OPADD 0 /* ORDER TM, ORDER OP */
+#define LUA_OPSUB 1
+#define LUA_OPMUL 2
+#define LUA_OPMOD 3
+#define LUA_OPPOW 4
+#define LUA_OPDIV 5
+#define LUA_OPIDIV 6
+#define LUA_OPBAND 7
+#define LUA_OPBOR 8
+#define LUA_OPBXOR 9
+#define LUA_OPSHL 10
+#define LUA_OPSHR 11
+#define LUA_OPUNM 12
+#define LUA_OPBNOT 13
+
+LUA_API void (lua_arith) (lua_State *L, int op);
+
+#define LUA_OPEQ 0
+#define LUA_OPLT 1
+#define LUA_OPLE 2
+
+LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2);
+LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op);
+
+
+/*
+** push functions (C -> stack)
+*/
+LUA_API void (lua_pushnil) (lua_State *L);
+LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n);
+LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n);
+LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len);
+LUA_API const char *(lua_pushstring) (lua_State *L, const char *s);
+LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt,
+ va_list argp);
+LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...);
+LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);
+LUA_API void (lua_pushboolean) (lua_State *L, int b);
+LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p);
+LUA_API int (lua_pushthread) (lua_State *L);
+
+
+/*
+** get functions (Lua -> stack)
+*/
+LUA_API int (lua_getglobal) (lua_State *L, const char *name);
+LUA_API int (lua_gettable) (lua_State *L, int idx);
+LUA_API int (lua_getfield) (lua_State *L, int idx, const char *k);
+LUA_API int (lua_geti) (lua_State *L, int idx, lua_Integer n);
+LUA_API int (lua_rawget) (lua_State *L, int idx);
+LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n);
+LUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p);
+
+LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec);
+LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz);
+LUA_API int (lua_getmetatable) (lua_State *L, int objindex);
+LUA_API int (lua_getuservalue) (lua_State *L, int idx);
+
+
+/*
+** set functions (stack -> Lua)
+*/
+LUA_API void (lua_setglobal) (lua_State *L, const char *name);
+LUA_API void (lua_settable) (lua_State *L, int idx);
+LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k);
+LUA_API void (lua_seti) (lua_State *L, int idx, lua_Integer n);
+LUA_API void (lua_rawset) (lua_State *L, int idx);
+LUA_API void (lua_rawseti) (lua_State *L, int idx, lua_Integer n);
+LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p);
+LUA_API int (lua_setmetatable) (lua_State *L, int objindex);
+LUA_API void (lua_setuservalue) (lua_State *L, int idx);
+
+
+/*
+** 'load' and 'call' functions (load and run Lua code)
+*/
+LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults,
+ lua_KContext ctx, lua_KFunction k);
+#define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL)
+
+LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc,
+ lua_KContext ctx, lua_KFunction k);
+#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL)
+
+LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt,
+ const char *chunkname, const char *mode);
+
+LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip);
+
+
+/*
+** coroutine functions
+*/
+LUA_API int (lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx,
+ lua_KFunction k);
+LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg);
+LUA_API int (lua_status) (lua_State *L);
+LUA_API int (lua_isyieldable) (lua_State *L);
+
+#define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL)
+
+
+/*
+** garbage-collection function and options
+*/
+
+#define LUA_GCSTOP 0
+#define LUA_GCRESTART 1
+#define LUA_GCCOLLECT 2
+#define LUA_GCCOUNT 3
+#define LUA_GCCOUNTB 4
+#define LUA_GCSTEP 5
+#define LUA_GCSETPAUSE 6
+#define LUA_GCSETSTEPMUL 7
+#define LUA_GCISRUNNING 9
+
+LUA_API int (lua_gc) (lua_State *L, int what, int data);
+
+
+/*
+** miscellaneous functions
+*/
+
+LUA_API int (lua_error) (lua_State *L);
+
+LUA_API int (lua_next) (lua_State *L, int idx);
+
+LUA_API void (lua_concat) (lua_State *L, int n);
+LUA_API void (lua_len) (lua_State *L, int idx);
+
+LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s);
+
+LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
+LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
+
+
+
+/*
+** {==============================================================
+** some useful macros
+** ===============================================================
+*/
+
+#define lua_getextraspace(L) ((void *)((char *)(L) - LUA_EXTRASPACE))
+
+#define lua_tonumber(L,i) lua_tonumberx(L,(i),NULL)
+#define lua_tointeger(L,i) lua_tointegerx(L,(i),NULL)
+
+#define lua_pop(L,n) lua_settop(L, -(n)-1)
+
+#define lua_newtable(L) lua_createtable(L, 0, 0)
+
+#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
+
+#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0)
+
+#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION)
+#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE)
+#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA)
+#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL)
+#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN)
+#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD)
+#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE)
+#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0)
+
+#define lua_pushliteral(L, s) lua_pushstring(L, "" s)
+
+#define lua_pushglobaltable(L) \
+ ((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS))
+
+#define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
+
+
+#define lua_insert(L,idx) lua_rotate(L, (idx), 1)
+
+#define lua_remove(L,idx) (lua_rotate(L, (idx), -1), lua_pop(L, 1))
+
+#define lua_replace(L,idx) (lua_copy(L, -1, (idx)), lua_pop(L, 1))
+
+/* }============================================================== */
+
+
+/*
+** {==============================================================
+** compatibility macros for unsigned conversions
+** ===============================================================
+*/
+#if defined(LUA_COMPAT_APIINTCASTS)
+
+#define lua_pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n))
+#define lua_tounsignedx(L,i,is) ((lua_Unsigned)lua_tointegerx(L,i,is))
+#define lua_tounsigned(L,i) lua_tounsignedx(L,(i),NULL)
+
+#endif
+/* }============================================================== */
+
+/*
+** {======================================================================
+** Debug API
+** =======================================================================
+*/
+
+
+/*
+** Event codes
+*/
+#define LUA_HOOKCALL 0
+#define LUA_HOOKRET 1
+#define LUA_HOOKLINE 2
+#define LUA_HOOKCOUNT 3
+#define LUA_HOOKTAILCALL 4
+
+
+/*
+** Event masks
+*/
+#define LUA_MASKCALL (1 << LUA_HOOKCALL)
+#define LUA_MASKRET (1 << LUA_HOOKRET)
+#define LUA_MASKLINE (1 << LUA_HOOKLINE)
+#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
+
+typedef struct lua_Debug lua_Debug; /* activation record */
+
+
+/* Functions to be called by the debugger in specific events */
+typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
+
+
+LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);
+LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);
+LUA_API const char *(lua_getlocal) (lua_State *L, const lua_Debug *ar, int n);
+LUA_API const char *(lua_setlocal) (lua_State *L, const lua_Debug *ar, int n);
+LUA_API const char *(lua_getupvalue) (lua_State *L, int funcindex, int n);
+LUA_API const char *(lua_setupvalue) (lua_State *L, int funcindex, int n);
+
+LUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n);
+LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1,
+ int fidx2, int n2);
+
+LUA_API void (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count);
+LUA_API lua_Hook (lua_gethook) (lua_State *L);
+LUA_API int (lua_gethookmask) (lua_State *L);
+LUA_API int (lua_gethookcount) (lua_State *L);
+
+
+struct lua_Debug {
+ int event;
+ const char *name; /* (n) */
+ const char *namewhat; /* (n) 'global', 'local', 'field', 'method' */
+ const char *what; /* (S) 'Lua', 'C', 'main', 'tail' */
+ const char *source; /* (S) */
+ int currentline; /* (l) */
+ int linedefined; /* (S) */
+ int lastlinedefined; /* (S) */
+ unsigned char nups; /* (u) number of upvalues */
+ unsigned char nparams;/* (u) number of parameters */
+ char isvararg; /* (u) */
+ char istailcall; /* (t) */
+ char short_src[LUA_IDSIZE]; /* (S) */
+ /* private part */
+ struct CallInfo *i_ci; /* active function */
+};
+
+/* }====================================================================== */
+
+
+/******************************************************************************
+* Copyright (C) 1994-2016 Lua.org, PUC-Rio.
+*
+* 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.
+******************************************************************************/
+
+
+#endif
diff --git a/src/external/lua/include/lua.hpp b/src/external/lua/include/lua.hpp
new file mode 100644
index 00000000..ec417f59
--- /dev/null
+++ b/src/external/lua/include/lua.hpp
@@ -0,0 +1,9 @@
+// lua.hpp
+// Lua header files for C++
+// <<extern "C">> not supplied automatically because Lua also compiles as C++
+
+extern "C" {
+#include "lua.h"
+#include "lualib.h"
+#include "lauxlib.h"
+}
diff --git a/src/external/lua/include/luaconf.h b/src/external/lua/include/luaconf.h
new file mode 100644
index 00000000..867e9cb1
--- /dev/null
+++ b/src/external/lua/include/luaconf.h
@@ -0,0 +1,769 @@
+/*
+** $Id: luaconf.h,v 1.255 2016/05/01 20:06:09 roberto Exp $
+** Configuration file for Lua
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef luaconf_h
+#define luaconf_h
+
+#include <limits.h>
+#include <stddef.h>
+
+
+/*
+** ===================================================================
+** Search for "@@" to find all configurable definitions.
+** ===================================================================
+*/
+
+
+/*
+** {====================================================================
+** System Configuration: macros to adapt (if needed) Lua to some
+** particular platform, for instance compiling it with 32-bit numbers or
+** restricting it to C89.
+** =====================================================================
+*/
+
+/*
+@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. You
+** can also define LUA_32BITS in the make file, but changing here you
+** ensure that all software connected to Lua will be compiled with the
+** same configuration.
+*/
+/* #define LUA_32BITS */
+
+
+/*
+@@ LUA_USE_C89 controls the use of non-ISO-C89 features.
+** Define it if you want Lua to avoid the use of a few C99 features
+** or Windows-specific features on Windows.
+*/
+/* #define LUA_USE_C89 */
+
+
+/*
+** By default, Lua on Windows use (some) specific Windows features
+*/
+#if !defined(LUA_USE_C89) && defined(_WIN32) && !defined(_WIN32_WCE)
+#define LUA_USE_WINDOWS /* enable goodies for regular Windows */
+#endif
+
+
+#if defined(LUA_USE_WINDOWS)
+#define LUA_DL_DLL /* enable support for DLL */
+#define LUA_USE_C89 /* broadly, Windows is C89 */
+#endif
+
+
+#if defined(LUA_USE_LINUX)
+#define LUA_USE_POSIX
+#define LUA_USE_DLOPEN /* needs an extra library: -ldl */
+#define LUA_USE_READLINE /* needs some extra libraries */
+#endif
+
+
+#if defined(LUA_USE_MACOSX)
+#define LUA_USE_POSIX
+#define LUA_USE_DLOPEN /* MacOS does not need -ldl */
+#define LUA_USE_READLINE /* needs an extra library: -lreadline */
+#endif
+
+
+/*
+@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for
+** C89 ('long' and 'double'); Windows always has '__int64', so it does
+** not need to use this case.
+*/
+#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS)
+#define LUA_C89_NUMBERS
+#endif
+
+
+
+/*
+@@ LUAI_BITSINT defines the (minimum) number of bits in an 'int'.
+*/
+/* avoid undefined shifts */
+#if ((INT_MAX >> 15) >> 15) >= 1
+#define LUAI_BITSINT 32
+#else
+/* 'int' always must have at least 16 bits */
+#define LUAI_BITSINT 16
+#endif
+
+
+/*
+@@ LUA_INT_TYPE defines the type for Lua integers.
+@@ LUA_FLOAT_TYPE defines the type for Lua floats.
+** Lua should work fine with any mix of these options (if supported
+** by your C compiler). The usual configurations are 64-bit integers
+** and 'double' (the default), 32-bit integers and 'float' (for
+** restricted platforms), and 'long'/'double' (for C compilers not
+** compliant with C99, which may not have support for 'long long').
+*/
+
+/* predefined options for LUA_INT_TYPE */
+#define LUA_INT_INT 1
+#define LUA_INT_LONG 2
+#define LUA_INT_LONGLONG 3
+
+/* predefined options for LUA_FLOAT_TYPE */
+#define LUA_FLOAT_FLOAT 1
+#define LUA_FLOAT_DOUBLE 2
+#define LUA_FLOAT_LONGDOUBLE 3
+
+#if defined(LUA_32BITS) /* { */
+/*
+** 32-bit integers and 'float'
+*/
+#if LUAI_BITSINT >= 32 /* use 'int' if big enough */
+#define LUA_INT_TYPE LUA_INT_INT
+#else /* otherwise use 'long' */
+#define LUA_INT_TYPE LUA_INT_LONG
+#endif
+#define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT
+
+#elif defined(LUA_C89_NUMBERS) /* }{ */
+/*
+** largest types available for C89 ('long' and 'double')
+*/
+#define LUA_INT_TYPE LUA_INT_LONG
+#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
+
+#endif /* } */
+
+
+/*
+** default configuration for 64-bit Lua ('long long' and 'double')
+*/
+#if !defined(LUA_INT_TYPE)
+#define LUA_INT_TYPE LUA_INT_LONGLONG
+#endif
+
+#if !defined(LUA_FLOAT_TYPE)
+#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
+#endif
+
+/* }================================================================== */
+
+
+
+
+/*
+** {==================================================================
+** Configuration for Paths.
+** ===================================================================
+*/
+
+/*
+@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for
+** Lua libraries.
+@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for
+** C libraries.
+** CHANGE them if your machine has a non-conventional directory
+** hierarchy or if you want to install your libraries in
+** non-conventional directories.
+*/
+#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
+#if defined(_WIN32) /* { */
+/*
+** In Windows, any exclamation mark ('!') in the path is replaced by the
+** path of the directory of the executable file of the current process.
+*/
+#define LUA_LDIR "!\\lua\\"
+#define LUA_CDIR "!\\"
+#define LUA_SHRDIR "!\\..\\share\\lua\\" LUA_VDIR "\\"
+#define LUA_PATH_DEFAULT \
+ LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \
+ LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \
+ LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \
+ ".\\?.lua;" ".\\?\\init.lua"
+#define LUA_CPATH_DEFAULT \
+ LUA_CDIR"?.dll;" \
+ LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \
+ LUA_CDIR"loadall.dll;" ".\\?.dll;" \
+ LUA_CDIR"?53.dll;" ".\\?53.dll"
+
+#else /* }{ */
+
+#define LUA_ROOT "/usr/local/"
+#define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR "/"
+#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR "/"
+#define LUA_PATH_DEFAULT \
+ LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \
+ LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" \
+ "./?.lua;" "./?/init.lua"
+#define LUA_CPATH_DEFAULT \
+ LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so;" \
+ LUA_CDIR"lib?53.so;" "./lib?53.so"
+#endif /* } */
+
+
+/*
+@@ LUA_DIRSEP is the directory separator (for submodules).
+** CHANGE it if your machine does not use "/" as the directory separator
+** and is not Windows. (On Windows Lua automatically uses "\".)
+*/
+#if defined(_WIN32)
+#define LUA_DIRSEP "\\"
+#else
+#define LUA_DIRSEP "/"
+#endif
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Marks for exported symbols in the C code
+** ===================================================================
+*/
+
+/*
+@@ LUA_API is a mark for all core API functions.
+@@ LUALIB_API is a mark for all auxiliary library functions.
+@@ LUAMOD_API is a mark for all standard library opening functions.
+** CHANGE them if you need to define those functions in some special way.
+** For instance, if you want to create one Windows DLL with the core and
+** the libraries, you may want to use the following definition (define
+** LUA_BUILD_AS_DLL to get it).
+*/
+#if defined(LUA_BUILD_AS_DLL) /* { */
+
+#if defined(LUA_CORE) || defined(LUA_LIB) /* { */
+#define LUA_API __declspec(dllexport)
+#else /* }{ */
+#define LUA_API __declspec(dllimport)
+#endif /* } */
+
+#else /* }{ */
+
+#define LUA_API extern
+
+#endif /* } */
+
+
+/* more often than not the libs go together with the core */
+#define LUALIB_API LUA_API
+#define LUAMOD_API LUALIB_API
+
+
+/*
+@@ LUAI_FUNC is a mark for all extern functions that are not to be
+** exported to outside modules.
+@@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables
+** that are not to be exported to outside modules (LUAI_DDEF for
+** definitions and LUAI_DDEC for declarations).
+** CHANGE them if you need to mark them in some special way. Elf/gcc
+** (versions 3.2 and later) mark them as "hidden" to optimize access
+** when Lua is compiled as a shared library. Not all elf targets support
+** this attribute. Unfortunately, gcc does not offer a way to check
+** whether the target offers that support, and those without support
+** give a warning about it. To avoid these warnings, change to the
+** default definition.
+*/
+#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \
+ defined(__ELF__) /* { */
+#define LUAI_FUNC __attribute__((visibility("hidden"))) extern
+#else /* }{ */
+#define LUAI_FUNC extern
+#endif /* } */
+
+#define LUAI_DDEC LUAI_FUNC
+#define LUAI_DDEF /* empty */
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Compatibility with previous versions
+** ===================================================================
+*/
+
+/*
+@@ LUA_COMPAT_5_2 controls other macros for compatibility with Lua 5.2.
+@@ LUA_COMPAT_5_1 controls other macros for compatibility with Lua 5.1.
+** You can define it to get all options, or change specific options
+** to fit your specific needs.
+*/
+#if defined(LUA_COMPAT_5_2) /* { */
+
+/*
+@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated
+** functions in the mathematical library.
+*/
+#define LUA_COMPAT_MATHLIB
+
+/*
+@@ LUA_COMPAT_BITLIB controls the presence of library 'bit32'.
+*/
+#define LUA_COMPAT_BITLIB
+
+/*
+@@ LUA_COMPAT_IPAIRS controls the effectiveness of the __ipairs metamethod.
+*/
+#define LUA_COMPAT_IPAIRS
+
+/*
+@@ LUA_COMPAT_APIINTCASTS controls the presence of macros for
+** manipulating other integer types (lua_pushunsigned, lua_tounsigned,
+** luaL_checkint, luaL_checklong, etc.)
+*/
+#define LUA_COMPAT_APIINTCASTS
+
+#endif /* } */
+
+
+#if defined(LUA_COMPAT_5_1) /* { */
+
+/* Incompatibilities from 5.2 -> 5.3 */
+#define LUA_COMPAT_MATHLIB
+#define LUA_COMPAT_APIINTCASTS
+
+/*
+@@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'.
+** You can replace it with 'table.unpack'.
+*/
+#define LUA_COMPAT_UNPACK
+
+/*
+@@ LUA_COMPAT_LOADERS controls the presence of table 'package.loaders'.
+** You can replace it with 'package.searchers'.
+*/
+#define LUA_COMPAT_LOADERS
+
+/*
+@@ macro 'lua_cpcall' emulates deprecated function lua_cpcall.
+** You can call your C function directly (with light C functions).
+*/
+#define lua_cpcall(L,f,u) \
+ (lua_pushcfunction(L, (f)), \
+ lua_pushlightuserdata(L,(u)), \
+ lua_pcall(L,1,0,0))
+
+
+/*
+@@ LUA_COMPAT_LOG10 defines the function 'log10' in the math library.
+** You can rewrite 'log10(x)' as 'log(x, 10)'.
+*/
+#define LUA_COMPAT_LOG10
+
+/*
+@@ LUA_COMPAT_LOADSTRING defines the function 'loadstring' in the base
+** library. You can rewrite 'loadstring(s)' as 'load(s)'.
+*/
+#define LUA_COMPAT_LOADSTRING
+
+/*
+@@ LUA_COMPAT_MAXN defines the function 'maxn' in the table library.
+*/
+#define LUA_COMPAT_MAXN
+
+/*
+@@ The following macros supply trivial compatibility for some
+** changes in the API. The macros themselves document how to
+** change your code to avoid using them.
+*/
+#define lua_strlen(L,i) lua_rawlen(L, (i))
+
+#define lua_objlen(L,i) lua_rawlen(L, (i))
+
+#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ)
+#define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT)
+
+/*
+@@ LUA_COMPAT_MODULE controls compatibility with previous
+** module functions 'module' (Lua) and 'luaL_register' (C).
+*/
+#define LUA_COMPAT_MODULE
+
+#endif /* } */
+
+
+/*
+@@ LUA_COMPAT_FLOATSTRING makes Lua format integral floats without a
+@@ a float mark ('.0').
+** This macro is not on by default even in compatibility mode,
+** because this is not really an incompatibility.
+*/
+/* #define LUA_COMPAT_FLOATSTRING */
+
+/* }================================================================== */
+
+
+
+/*
+** {==================================================================
+** Configuration for Numbers.
+** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_*
+** satisfy your needs.
+** ===================================================================
+*/
+
+/*
+@@ LUA_NUMBER is the floating-point type used by Lua.
+@@ LUAI_UACNUMBER is the result of an 'usual argument conversion'
+@@ over a floating number.
+@@ l_mathlim(x) corrects limit name 'x' to the proper float type
+** by prefixing it with one of FLT/DBL/LDBL.
+@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats.
+@@ LUA_NUMBER_FMT is the format for writing floats.
+@@ lua_number2str converts a float to a string.
+@@ l_mathop allows the addition of an 'l' or 'f' to all math operations.
+@@ l_floor takes the floor of a float.
+@@ lua_str2number converts a decimal numeric string to a number.
+*/
+
+
+/* The following definitions are good for most cases here */
+
+#define l_floor(x) (l_mathop(floor)(x))
+
+#define lua_number2str(s,sz,n) l_sprintf((s), sz, LUA_NUMBER_FMT, (n))
+
+/*
+@@ lua_numbertointeger converts a float number to an integer, or
+** returns 0 if float is not within the range of a lua_Integer.
+** (The range comparisons are tricky because of rounding. The tests
+** here assume a two-complement representation, where MININTEGER always
+** has an exact representation as a float; MAXINTEGER may not have one,
+** and therefore its conversion to float may have an ill-defined value.)
+*/
+#define lua_numbertointeger(n,p) \
+ ((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \
+ (n) < -(LUA_NUMBER)(LUA_MININTEGER) && \
+ (*(p) = (LUA_INTEGER)(n), 1))
+
+
+/* now the variable definitions */
+
+#if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */
+
+#define LUA_NUMBER float
+
+#define l_mathlim(n) (FLT_##n)
+
+#define LUAI_UACNUMBER double
+
+#define LUA_NUMBER_FRMLEN ""
+#define LUA_NUMBER_FMT "%.7g"
+
+#define l_mathop(op) op##f
+
+#define lua_str2number(s,p) strtof((s), (p))
+
+
+#elif LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE /* }{ long double */
+
+#define LUA_NUMBER long double
+
+#define l_mathlim(n) (LDBL_##n)
+
+#define LUAI_UACNUMBER long double
+
+#define LUA_NUMBER_FRMLEN "L"
+#define LUA_NUMBER_FMT "%.19Lg"
+
+#define l_mathop(op) op##l
+
+#define lua_str2number(s,p) strtold((s), (p))
+
+#elif LUA_FLOAT_TYPE == LUA_FLOAT_DOUBLE /* }{ double */
+
+#define LUA_NUMBER double
+
+#define l_mathlim(n) (DBL_##n)
+
+#define LUAI_UACNUMBER double
+
+#define LUA_NUMBER_FRMLEN ""
+#define LUA_NUMBER_FMT "%.14g"
+
+#define l_mathop(op) op
+
+#define lua_str2number(s,p) strtod((s), (p))
+
+#else /* }{ */
+
+#error "numeric float type not defined"
+
+#endif /* } */
+
+
+
+/*
+@@ LUA_INTEGER is the integer type used by Lua.
+**
+@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER.
+**
+@@ LUAI_UACINT is the result of an 'usual argument conversion'
+@@ over a lUA_INTEGER.
+@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers.
+@@ LUA_INTEGER_FMT is the format for writing integers.
+@@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER.
+@@ LUA_MININTEGER is the minimum value for a LUA_INTEGER.
+@@ lua_integer2str converts an integer to a string.
+*/
+
+
+/* The following definitions are good for most cases here */
+
+#define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d"
+#define lua_integer2str(s,sz,n) l_sprintf((s), sz, LUA_INTEGER_FMT, (n))
+
+#define LUAI_UACINT LUA_INTEGER
+
+/*
+** use LUAI_UACINT here to avoid problems with promotions (which
+** can turn a comparison between unsigneds into a signed comparison)
+*/
+#define LUA_UNSIGNED unsigned LUAI_UACINT
+
+
+/* now the variable definitions */
+
+#if LUA_INT_TYPE == LUA_INT_INT /* { int */
+
+#define LUA_INTEGER int
+#define LUA_INTEGER_FRMLEN ""
+
+#define LUA_MAXINTEGER INT_MAX
+#define LUA_MININTEGER INT_MIN
+
+#elif LUA_INT_TYPE == LUA_INT_LONG /* }{ long */
+
+#define LUA_INTEGER long
+#define LUA_INTEGER_FRMLEN "l"
+
+#define LUA_MAXINTEGER LONG_MAX
+#define LUA_MININTEGER LONG_MIN
+
+#elif LUA_INT_TYPE == LUA_INT_LONGLONG /* }{ long long */
+
+/* use presence of macro LLONG_MAX as proxy for C99 compliance */
+#if defined(LLONG_MAX) /* { */
+/* use ISO C99 stuff */
+
+#define LUA_INTEGER long long
+#define LUA_INTEGER_FRMLEN "ll"
+
+#define LUA_MAXINTEGER LLONG_MAX
+#define LUA_MININTEGER LLONG_MIN
+
+#elif defined(LUA_USE_WINDOWS) /* }{ */
+/* in Windows, can use specific Windows types */
+
+#define LUA_INTEGER __int64
+#define LUA_INTEGER_FRMLEN "I64"
+
+#define LUA_MAXINTEGER _I64_MAX
+#define LUA_MININTEGER _I64_MIN
+
+#else /* }{ */
+
+#error "Compiler does not support 'long long'. Use option '-DLUA_32BITS' \
+ or '-DLUA_C89_NUMBERS' (see file 'luaconf.h' for details)"
+
+#endif /* } */
+
+#else /* }{ */
+
+#error "numeric integer type not defined"
+
+#endif /* } */
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Dependencies with C99 and other C details
+** ===================================================================
+*/
+
+/*
+@@ l_sprintf is equivalent to 'snprintf' or 'sprintf' in C89.
+** (All uses in Lua have only one format item.)
+*/
+#if !defined(LUA_USE_C89)
+#define l_sprintf(s,sz,f,i) snprintf(s,sz,f,i)
+#else
+#define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s,f,i))
+#endif
+
+
+/*
+@@ lua_strx2number converts an hexadecimal numeric string to a number.
+** In C99, 'strtod' does that conversion. Otherwise, you can
+** leave 'lua_strx2number' undefined and Lua will provide its own
+** implementation.
+*/
+#if !defined(LUA_USE_C89)
+#define lua_strx2number(s,p) lua_str2number(s,p)
+#endif
+
+
+/*
+@@ lua_number2strx converts a float to an hexadecimal numeric string.
+** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that.
+** Otherwise, you can leave 'lua_number2strx' undefined and Lua will
+** provide its own implementation.
+*/
+#if !defined(LUA_USE_C89)
+#define lua_number2strx(L,b,sz,f,n) ((void)L, l_sprintf(b,sz,f,n))
+#endif
+
+
+/*
+** 'strtof' and 'opf' variants for math functions are not valid in
+** C89. Otherwise, the macro 'HUGE_VALF' is a good proxy for testing the
+** availability of these variants. ('math.h' is already included in
+** all files that use these macros.)
+*/
+#if defined(LUA_USE_C89) || (defined(HUGE_VAL) && !defined(HUGE_VALF))
+#undef l_mathop /* variants not available */
+#undef lua_str2number
+#define l_mathop(op) (lua_Number)op /* no variant */
+#define lua_str2number(s,p) ((lua_Number)strtod((s), (p)))
+#endif
+
+
+/*
+@@ LUA_KCONTEXT is the type of the context ('ctx') for continuation
+** functions. It must be a numerical type; Lua will use 'intptr_t' if
+** available, otherwise it will use 'ptrdiff_t' (the nearest thing to
+** 'intptr_t' in C89)
+*/
+#define LUA_KCONTEXT ptrdiff_t
+
+#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
+ __STDC_VERSION__ >= 199901L
+#include <stdint.h>
+#if defined(INTPTR_MAX) /* even in C99 this type is optional */
+#undef LUA_KCONTEXT
+#define LUA_KCONTEXT intptr_t
+#endif
+#endif
+
+
+/*
+@@ lua_getlocaledecpoint gets the locale "radix character" (decimal point).
+** Change that if you do not want to use C locales. (Code using this
+** macro must include header 'locale.h'.)
+*/
+#if !defined(lua_getlocaledecpoint)
+#define lua_getlocaledecpoint() (localeconv()->decimal_point[0])
+#endif
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Language Variations
+** =====================================================================
+*/
+
+/*
+@@ LUA_NOCVTN2S/LUA_NOCVTS2N control how Lua performs some
+** coercions. Define LUA_NOCVTN2S to turn off automatic coercion from
+** numbers to strings. Define LUA_NOCVTS2N to turn off automatic
+** coercion from strings to numbers.
+*/
+/* #define LUA_NOCVTN2S */
+/* #define LUA_NOCVTS2N */
+
+
+/*
+@@ LUA_USE_APICHECK turns on several consistency checks on the C API.
+** Define it as a help when debugging C code.
+*/
+#if defined(LUA_USE_APICHECK)
+#include <assert.h>
+#define luai_apicheck(l,e) assert(e)
+#endif
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Macros that affect the API and must be stable (that is, must be the
+** same when you compile Lua and when you compile code that links to
+** Lua). You probably do not want/need to change them.
+** =====================================================================
+*/
+
+/*
+@@ LUAI_MAXSTACK limits the size of the Lua stack.
+** CHANGE it if you need a different limit. This limit is arbitrary;
+** its only purpose is to stop Lua from consuming unlimited stack
+** space (and to reserve some numbers for pseudo-indices).
+*/
+#if LUAI_BITSINT >= 32
+#define LUAI_MAXSTACK 1000000
+#else
+#define LUAI_MAXSTACK 15000
+#endif
+
+
+/*
+@@ LUA_EXTRASPACE defines the size of a raw memory area associated with
+** a Lua state with very fast access.
+** CHANGE it if you need a different size.
+*/
+#define LUA_EXTRASPACE (sizeof(void *))
+
+
+/*
+@@ LUA_IDSIZE gives the maximum size for the description of the source
+@@ of a function in debug information.
+** CHANGE it if you want a different size.
+*/
+#define LUA_IDSIZE 60
+
+
+/*
+@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
+** CHANGE it if it uses too much C-stack space. (For long double,
+** 'string.format("%.99f", 1e4932)' needs ~5030 bytes, so a
+** smaller buffer would force a memory allocation for each call to
+** 'string.format'.)
+*/
+#if defined(LUA_FLOAT_LONGDOUBLE)
+#define LUAL_BUFFERSIZE 8192
+#else
+#define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer)))
+#endif
+
+/* }================================================================== */
+
+
+/*
+@@ LUA_QL describes how error messages quote program elements.
+** Lua does not use these macros anymore; they are here for
+** compatibility only.
+*/
+#define LUA_QL(x) "'" x "'"
+#define LUA_QS LUA_QL("%s")
+
+
+
+
+/* =================================================================== */
+
+/*
+** Local configuration. You can use this space to add your redefinitions
+** without modifying the main part of the file.
+*/
+
+
+
+
+
+#endif
+
diff --git a/src/external/lua/include/lualib.h b/src/external/lua/include/lualib.h
new file mode 100644
index 00000000..5165c0fb
--- /dev/null
+++ b/src/external/lua/include/lualib.h
@@ -0,0 +1,58 @@
+/*
+** $Id: lualib.h,v 1.44 2014/02/06 17:32:33 roberto Exp $
+** Lua standard libraries
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lualib_h
+#define lualib_h
+
+#include "lua.h"
+
+
+
+LUAMOD_API int (luaopen_base) (lua_State *L);
+
+#define LUA_COLIBNAME "coroutine"
+LUAMOD_API int (luaopen_coroutine) (lua_State *L);
+
+#define LUA_TABLIBNAME "table"
+LUAMOD_API int (luaopen_table) (lua_State *L);
+
+#define LUA_IOLIBNAME "io"
+LUAMOD_API int (luaopen_io) (lua_State *L);
+
+#define LUA_OSLIBNAME "os"
+LUAMOD_API int (luaopen_os) (lua_State *L);
+
+#define LUA_STRLIBNAME "string"
+LUAMOD_API int (luaopen_string) (lua_State *L);
+
+#define LUA_UTF8LIBNAME "utf8"
+LUAMOD_API int (luaopen_utf8) (lua_State *L);
+
+#define LUA_BITLIBNAME "bit32"
+LUAMOD_API int (luaopen_bit32) (lua_State *L);
+
+#define LUA_MATHLIBNAME "math"
+LUAMOD_API int (luaopen_math) (lua_State *L);
+
+#define LUA_DBLIBNAME "debug"
+LUAMOD_API int (luaopen_debug) (lua_State *L);
+
+#define LUA_LOADLIBNAME "package"
+LUAMOD_API int (luaopen_package) (lua_State *L);
+
+
+/* open all previous libraries */
+LUALIB_API void (luaL_openlibs) (lua_State *L);
+
+
+
+#if !defined(lua_assert)
+#define lua_assert(x) ((void)0)
+#endif
+
+
+#endif
diff --git a/src/external/lua/lib/liblua53.a b/src/external/lua/lib/liblua53.a
new file mode 100644
index 00000000..e51c0c80
--- /dev/null
+++ b/src/external/lua/lib/liblua53.a
Binary files differ
diff --git a/src/external/lua/lib/liblua53dll.a b/src/external/lua/lib/liblua53dll.a
new file mode 100644
index 00000000..32646db3
--- /dev/null
+++ b/src/external/lua/lib/liblua53dll.a
Binary files differ
diff --git a/src/external/openal_soft/include/AL/alext.h b/src/external/openal_soft/include/AL/alext.h
index 6af581aa..0090c804 100644
--- a/src/external/openal_soft/include/AL/alext.h
+++ b/src/external/openal_soft/include/AL/alext.h
@@ -431,6 +431,11 @@ ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCi
#endif
#endif
+#ifndef AL_SOFT_gain_clamp_ex
+#define AL_SOFT_gain_clamp_ex 1
+#define AL_GAIN_LIMIT_SOFT 0x200E
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/src/external/openal_soft/lib/win32/libOpenAL32.a b/src/external/openal_soft/lib/win32/libOpenAL32.a
new file mode 100644
index 00000000..3c0df3c7
--- /dev/null
+++ b/src/external/openal_soft/lib/win32/libOpenAL32.a
Binary files differ
diff --git a/src/external/pthread/lib/pthreadGC2.dll b/src/external/pthread/lib/pthreadGC2.dll
new file mode 100644
index 00000000..67b9289d
--- /dev/null
+++ b/src/external/pthread/lib/pthreadGC2.dll
Binary files differ