aboutsummaryrefslogtreecommitdiff
path: root/test/072_coord_co
diff options
context:
space:
mode:
authorSebastiano Tronto <sebastiano@tronto.net>2026-03-01 18:07:44 +0000
committerSebastiano Tronto <sebastiano@tronto.net>2026-03-01 18:07:44 +0000
commitff0a9418672fbec935d9b58f81ad9ea719114177 (patch)
tree2c009a3ad206842b07b1cd758b8192e2154231e9 /test/072_coord_co
parentaf443edca17649a6f2e66707746f482caefe3d1a (diff)
downloadnissy-core-threads.tar.gz
nissy-core-threads.zip
Python path detection in Windowsthreads
Diffstat (limited to 'test/072_coord_co')
0 files changed, 0 insertions, 0 deletions

Generated with cgit - Back to sebastiano.tronto.net

ary='file diffstat' width='100%'> -rw-r--r--raylib/src/external/dr_flac.h12536
-rw-r--r--raylib/src/external/dr_mp3.h4837
-rw-r--r--raylib/src/external/dr_wav.h8815
-rw-r--r--raylib/src/external/glad.h8682
-rw-r--r--raylib/src/external/glad_gles2.h4774
-rw-r--r--raylib/src/external/glfw/.mailmap10
-rw-r--r--raylib/src/external/glfw/CMake/GenerateMappings.cmake48
-rw-r--r--raylib/src/external/glfw/CMake/Info.plist.in38
-rw-r--r--raylib/src/external/glfw/CMake/cmake_uninstall.cmake.in29
-rw-r--r--raylib/src/external/glfw/CMake/glfw3.pc.in13
-rw-r--r--raylib/src/external/glfw/CMake/glfw3Config.cmake.in3
-rw-r--r--raylib/src/external/glfw/CMake/i686-w64-mingw32-clang.cmake13
-rw-r--r--raylib/src/external/glfw/CMake/i686-w64-mingw32.cmake13
-rw-r--r--raylib/src/external/glfw/CMake/modules/FindEpollShim.cmake17
-rw-r--r--raylib/src/external/glfw/CMake/modules/FindOSMesa.cmake18
-rw-r--r--raylib/src/external/glfw/CMake/x86_64-w64-mingw32-clang.cmake13
-rw-r--r--raylib/src/external/glfw/CMake/x86_64-w64-mingw32.cmake13
-rw-r--r--raylib/src/external/glfw/CMakeLists.txt165
-rw-r--r--raylib/src/external/glfw/CONTRIBUTORS.md297
-rw-r--r--raylib/src/external/glfw/LICENSE.md23
-rw-r--r--raylib/src/external/glfw/README.md18
-rw-r--r--raylib/src/external/glfw/deps/getopt.c230
-rw-r--r--raylib/src/external/glfw/deps/getopt.h57
-rw-r--r--raylib/src/external/glfw/deps/glad/gl.h5996
-rw-r--r--raylib/src/external/glfw/deps/glad/gles2.h1805
-rw-r--r--raylib/src/external/glfw/deps/glad/vulkan.h6330
-rw-r--r--raylib/src/external/glfw/deps/mingw/_mingw_dxhelper.h117
-rw-r--r--raylib/src/external/glfw/deps/mingw/dinput.h2467
-rw-r--r--raylib/src/external/glfw/deps/mingw/xinput.h239
-rw-r--r--raylib/src/external/glfw/deps/wayland/fractional-scale-v1.xml102
-rw-r--r--raylib/src/external/glfw/deps/wayland/idle-inhibit-unstable-v1.xml83
-rw-r--r--raylib/src/external/glfw/deps/wayland/pointer-constraints-unstable-v1.xml339
-rw-r--r--raylib/src/external/glfw/deps/wayland/relative-pointer-unstable-v1.xml136
-rw-r--r--raylib/src/external/glfw/deps/wayland/viewporter.xml180
-rw-r--r--raylib/src/external/glfw/deps/wayland/wayland.xml3151
-rw-r--r--raylib/src/external/glfw/deps/wayland/xdg-activation-v1.xml200
-rw-r--r--raylib/src/external/glfw/deps/wayland/xdg-decoration-unstable-v1.xml156
-rw-r--r--raylib/src/external/glfw/deps/wayland/xdg-shell.xml1370
-rw-r--r--raylib/src/external/glfw/include/GLFW/glfw3.h6547
-rw-r--r--raylib/src/external/glfw/include/GLFW/glfw3native.h663
-rw-r--r--raylib/src/external/glfw/src/CMakeLists.txt368
-rw-r--r--raylib/src/external/glfw/src/cocoa_init.m696
-rw-r--r--raylib/src/external/glfw/src/cocoa_joystick.h49
-rw-r--r--raylib/src/external/glfw/src/cocoa_joystick.m485
-rw-r--r--raylib/src/external/glfw/src/cocoa_monitor.m644
-rw-r--r--raylib/src/external/glfw/src/cocoa_platform.h302
-rw-r--r--raylib/src/external/glfw/src/cocoa_time.c57
-rw-r--r--raylib/src/external/glfw/src/cocoa_time.h35
-rw-r--r--raylib/src/external/glfw/src/cocoa_window.m2072
-rw-r--r--raylib/src/external/glfw/src/context.c765
-rw-r--r--raylib/src/external/glfw/src/egl_context.c911
-rw-r--r--raylib/src/external/glfw/src/glfw.rc.in30
-rw-r--r--raylib/src/external/glfw/src/glx_context.c719
-rw-r--r--raylib/src/external/glfw/src/init.c528
-rw-r--r--raylib/src/external/glfw/src/input.c1505
-rw-r--r--raylib/src/external/glfw/src/internal.h1009
-rw-r--r--raylib/src/external/glfw/src/linux_joystick.c436
-rw-r--r--raylib/src/external/glfw/src/linux_joystick.h64
-rw-r--r--raylib/src/external/glfw/src/mappings.h1002
-rw-r--r--raylib/src/external/glfw/src/mappings.h.in82
-rw-r--r--raylib/src/external/glfw/src/monitor.c548
-rw-r--r--raylib/src/external/glfw/src/nsgl_context.m384
-rw-r--r--raylib/src/external/glfw/src/null_init.c264
-rw-r--r--raylib/src/external/glfw/src/null_joystick.c56
-rw-r--r--raylib/src/external/glfw/src/null_joystick.h32
-rw-r--r--raylib/src/external/glfw/src/null_monitor.c160
-rw-r--r--raylib/src/external/glfw/src/null_platform.h271
-rw-r--r--raylib/src/external/glfw/src/null_window.c720
-rw-r--r--raylib/src/external/glfw/src/osmesa_context.c383
-rw-r--r--raylib/src/external/glfw/src/platform.c204
-rw-r--r--raylib/src/external/glfw/src/platform.h212
-rw-r--r--raylib/src/external/glfw/src/posix_module.c53
-rw-r--r--raylib/src/external/glfw/src/posix_poll.c83
-rw-r--r--raylib/src/external/glfw/src/posix_poll.h30
-rw-r--r--raylib/src/external/glfw/src/posix_thread.c107
-rw-r--r--raylib/src/external/glfw/src/posix_thread.h49
-rw-r--r--raylib/src/external/glfw/src/posix_time.c65
-rw-r--r--raylib/src/external/glfw/src/posix_time.h41
-rw-r--r--raylib/src/external/glfw/src/vulkan.c328
-rw-r--r--raylib/src/external/glfw/src/wgl_context.c798
-rw-r--r--raylib/src/external/glfw/src/win32_init.c732
-rw-r--r--raylib/src/external/glfw/src/win32_joystick.c767
-rw-r--r--raylib/src/external/glfw/src/win32_joystick.h51
-rw-r--r--raylib/src/external/glfw/src/win32_module.c51
-rw-r--r--raylib/src/external/glfw/src/win32_monitor.c569
-rw-r--r--raylib/src/external/glfw/src/win32_platform.h627
-rw-r--r--raylib/src/external/glfw/src/win32_thread.c100
-rw-r--r--raylib/src/external/glfw/src/win32_thread.h53
-rw-r--r--raylib/src/external/glfw/src/win32_time.c54
-rw-r--r--raylib/src/external/glfw/src/win32_time.h43
-rw-r--r--raylib/src/external/glfw/src/win32_window.c2594
-rw-r--r--raylib/src/external/glfw/src/window.c1172
-rw-r--r--raylib/src/external/glfw/src/wl_init.c1004
-rw-r--r--raylib/src/external/glfw/src/wl_monitor.c274
-rw-r--r--raylib/src/external/glfw/src/wl_platform.h691
-rw-r--r--raylib/src/external/glfw/src/wl_window.c3309
-rw-r--r--raylib/src/external/glfw/src/x11_init.c1657
-rw-r--r--raylib/src/external/glfw/src/x11_monitor.c641
-rw-r--r--raylib/src/external/glfw/src/x11_platform.h1004
-rw-r--r--raylib/src/external/glfw/src/x11_window.c3358
-rw-r--r--raylib/src/external/glfw/src/xkb_unicode.c943
-rw-r--r--raylib/src/external/glfw/src/xkb_unicode.h30
-rw-r--r--raylib/src/external/jar_mod.h1596
-rw-r--r--raylib/src/external/jar_xm.h2471
-rw-r--r--raylib/src/external/m3d.h6547
-rw-r--r--raylib/src/external/miniaudio.h92633
-rw-r--r--raylib/src/external/msf_gif.h717
-rw-r--r--raylib/src/external/par_shapes.h2155
-rw-r--r--raylib/src/external/qoa.h742
-rw-r--r--raylib/src/external/qoaplay.c278
-rw-r--r--raylib/src/external/qoi.h649
-rw-r--r--raylib/src/external/rl_gputex.h826
-rw-r--r--raylib/src/external/rprand.h311
-rw-r--r--raylib/src/external/sdefl.h790
-rw-r--r--raylib/src/external/sinfl.h629
-rw-r--r--raylib/src/external/stb_image.h7988
-rw-r--r--raylib/src/external/stb_image_resize2.h10601
-rw-r--r--raylib/src/external/stb_image_write.h1724
-rw-r--r--raylib/src/external/stb_perlin.h428
-rw-r--r--raylib/src/external/stb_rect_pack.h623
-rw-r--r--raylib/src/external/stb_truetype.h5079
-rw-r--r--raylib/src/external/stb_vorbis.c5584
-rw-r--r--raylib/src/external/tinyobj_loader_c.h1594
-rw-r--r--raylib/src/external/vox_loader.h727
-rw-r--r--raylib/src/external/win32_clipboard.h374
-rw-r--r--raylib/src/minshell.html89
-rw-r--r--raylib/src/platforms/rcore_android.c1339
-rw-r--r--raylib/src/platforms/rcore_desktop_glfw.c1933
-rw-r--r--raylib/src/platforms/rcore_desktop_rgfw.c1387
-rw-r--r--raylib/src/platforms/rcore_desktop_sdl.c1978
-rw-r--r--raylib/src/platforms/rcore_drm.c1942
-rw-r--r--raylib/src/platforms/rcore_template.c597
-rw-r--r--raylib/src/platforms/rcore_web.c1792
-rw-r--r--raylib/src/raudio.c2879
-rw-r--r--raylib/src/raylib.dll.rc27
-rw-r--r--raylib/src/raylib.dll.rc.databin0 -> 11318 bytes-rw-r--r--raylib/src/raylib.h1708
-rw-r--r--raylib/src/raylib.icobin0 -> 6177 bytes-rw-r--r--raylib/src/raylib.rc27
-rw-r--r--raylib/src/raylib.rc.databin0 -> 11302 bytes-rw-r--r--raylib/src/raymath.h2941
-rw-r--r--raylib/src/rcamera.h555
-rw-r--r--raylib/src/rcore.c4070
-rw-r--r--raylib/src/rgestures.h555
-rw-r--r--raylib/src/rglfw.c148
-rw-r--r--raylib/src/rlgl.h5262
-rw-r--r--raylib/src/rmodels.c6796
-rw-r--r--raylib/src/rshapes.c2414
-rw-r--r--raylib/src/rtext.c2573
-rw-r--r--raylib/src/rtextures.c5548
-rw-r--r--raylib/src/shell.html338
-rw-r--r--raylib/src/utils.c510
-rw-r--r--raylib/src/utils.h81
161 files changed, 317024 insertions, 0 deletions
diff --git a/raylib/raylib.ha b/raylib/raylib.ha
new file mode 100644
index 0000000..65c1b51
--- /dev/null
+++ b/raylib/raylib.ha
@@ -0,0 +1,52 @@
1use types::c;
2
3export const MOUSE_BUTTON_LEFT = 0;
4export const MOUSE_BUTTON_RIGHT = 1;
5export const FLAG_WINDOW_RESIZABLE: uint = 4;
6
7export const KEY_N = 78;
8
9export type color = struct {
10 r: u8,
11 g: u8,
12 b: u8,
13 a: u8
14};
15
16export type vector2 = struct {
17 x: f32,
18 y: f32
19};
20
21export @symbol("WindowShouldClose") fn window_should_close() bool;
22export @symbol("BeginDrawing") fn begin_drawing() void;
23export @symbol("EndDrawing") fn end_drawing() void;
24export @symbol("ClearBackground") fn clear_background(color) void;
25export @symbol("DrawRectangleV") fn draw_rectangle_v(vector2, vector2, color) void;
26export @symbol("IsMouseButtonPressed") fn is_mouse_button_pressed(int) bool;
27export @symbol("GetMousePosition") fn get_mouse_position() vector2;
28export @symbol("GetScreenHeight") fn get_screen_height() int;
29export @symbol("GetScreenWidth") fn get_screen_width() int;
30export @symbol("SetConfigFlags") fn set_config_flags(uint) void;
31export @symbol("IsKeyPressed") fn is_key_pressed(int) bool;
32
33@symbol("InitWindow") fn InitWindow(int, int, *c::char) void;
34export fn init_window(width: int, height: int, title: str) void = {
35 let c_title = c::fromstr(title)!;
36 defer free(c_title);
37 InitWindow(width, height, c_title);
38};
39
40@symbol("DrawText") fn DrawText(*c::char, int, int, int, color) void;
41export fn draw_text(text: str, x: int, y: int, sz: int, c: color) void = {
42 let c_str = c::fromstr(text)!;
43 defer free(c_str);
44 DrawText(c_str, x, y, sz, c);
45};
46
47@symbol("MeasureText") fn MeasureText(*c::char, int) int;
48export fn measure_text(text: str, sz: int) int = {
49 let c_str = c::fromstr(text)!;
50 defer free(c_str);
51 return MeasureText(c_str, sz);
52};
diff --git a/raylib/src/CMakeLists.txt b/raylib/src/CMakeLists.txt
new file mode 100644
index 0000000..9735e26
--- /dev/null
+++ b/raylib/src/CMakeLists.txt
@@ -0,0 +1,132 @@
1# Setup the project and settings
2project(raylib C)
3set(PROJECT_VERSION 5.5.0)
4set(API_VERSION 550)
5
6include(GNUInstallDirs)
7include(JoinPaths)
8
9# Sets build type if not set by now
10if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
11 if(RAYLIB_IS_MAIN)
12 set(default_build_type Debug)
13 else()
14 message(WARNING "Default build type is not set (CMAKE_BUILD_TYPE)")
15 endif()
16
17 message(STATUS "Setting build type to '${default_build_type}' as none was specified.")
18
19 set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE)
20 set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
21endif()
22
23# Used as public API to be included into other projects
24set(raylib_public_headers
25 raylib.h
26 rlgl.h
27 raymath.h
28 )
29
30# Sources to be compiled
31set(raylib_sources
32 raudio.c
33 rcore.c
34 rmodels.c
35 rshapes.c
36 rtext.c
37 rtextures.c
38 utils.c
39 )
40
41# <root>/cmake/GlfwImport.cmake handles the details around the inclusion of glfw
42if (NOT ${PLATFORM} MATCHES "Web")
43 include(GlfwImport)
44endif ()
45
46# Sets additional platform options and link libraries for each platform
47# also selects the proper graphics API and version for that platform
48# Produces a variable LIBS_PRIVATE that will be used later
49include(LibraryConfigurations)
50
51if (SUPPORT_MODULE_RAUDIO)
52 MESSAGE(STATUS "Audio Backend: miniaudio")
53else ()
54 MESSAGE(STATUS "Audio Backend: None (-DCUSTOMIZE_BUILD=ON -DSUPPORT_MODULE_RAUDIO=OFF)")
55endif ()
56
57add_library(raylib ${raylib_sources} ${raylib_public_headers})
58
59if (NOT BUILD_SHARED_LIBS)
60 MESSAGE(STATUS "Building raylib static library")
61 add_library(raylib_static ALIAS raylib)
62else()
63 MESSAGE(STATUS "Building raylib shared library")
64 target_compile_definitions(raylib
65 PRIVATE $<BUILD_INTERFACE:BUILD_LIBTYPE_SHARED>
66 INTERFACE $<INSTALL_INTERFACE:USE_LIBTYPE_SHARED>
67 )
68endif()
69
70if (${PLATFORM} MATCHES "Web")
71 target_link_options(raylib PUBLIC "-sUSE_GLFW=3")
72 if(${GRAPHICS} MATCHES "GRAPHICS_API_OPENGL_ES3")
73 target_link_options(raylib PUBLIC "-sMIN_WEBGL_VERSION=2")
74 target_link_options(raylib PUBLIC "-sMAX_WEBGL_VERSION=2")
75 endif()
76endif()
77
78set_target_properties(raylib PROPERTIES
79 PUBLIC_HEADER "${raylib_public_headers}"
80 VERSION ${PROJECT_VERSION}
81 SOVERSION ${API_VERSION}
82 )
83
84if (WITH_PIC OR BUILD_SHARED_LIBS)
85 set_property(TARGET raylib PROPERTY POSITION_INDEPENDENT_CODE ON)
86endif ()
87
88if (BUILD_SHARED_LIBS)
89 # Hide raylib's symbols by default so RLAPI can expose them
90 set_property(TARGET raylib PROPERTY C_VISIBILITY_PRESET hidden)
91endif ()
92
93target_link_libraries(raylib "${LIBS_PRIVATE}")
94
95# Sets some compile time definitions for the pre-processor
96# If CUSTOMIZE_BUILD option is on you will not use config.h by default
97# and you will be able to select more build options
98include(CompileDefinitions)
99
100# Registering include directories
101target_include_directories(raylib
102 PUBLIC
103 $<INSTALL_INTERFACE:include>
104 $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
105 PRIVATE
106 ${CMAKE_CURRENT_SOURCE_DIR}
107 ${OPENGL_INCLUDE_DIR}
108 ${OPENAL_INCLUDE_DIR}
109 )
110
111# Copy the header files to the build directory for convenience
112file(COPY ${raylib_public_headers} DESTINATION "include")
113
114# Includes information on how the library will be installed on the system
115# when cmake --install is run
116include(InstallConfigurations)
117
118# Print the flags for the user
119if (DEFINED CMAKE_BUILD_TYPE)
120 message(STATUS "Generated build type: ${CMAKE_BUILD_TYPE}")
121else ()
122 message(STATUS "Generated config types: ${CMAKE_CONFIGURATION_TYPES}")
123endif ()
124
125message(STATUS "Compiling with the flags:")
126message(STATUS " PLATFORM=" ${PLATFORM_CPP})
127message(STATUS " GRAPHICS=" ${GRAPHICS})
128
129# Options if you want to create an installer using CPack
130include(PackConfigurations)
131
132enable_testing()
diff --git a/raylib/src/LICENSE b/raylib/src/LICENSE
new file mode 100644
index 0000000..e96f876
--- /dev/null
+++ b/raylib/src/LICENSE
@@ -0,0 +1,16 @@
1Copyright (c) 2013-2025 Ramon Santamaria (@raysan5)
2
3This software is provided "as-is", without any express or implied warranty. In no event
4will the authors be held liable for any damages arising from the use of this software.
5
6Permission is granted to anyone to use this software for any purpose, including commercial
7applications, and to alter it and redistribute it freely, subject to the following restrictions:
8
9 1. The origin of this software must not be misrepresented; you must not claim that you
10 wrote the original software. If you use this software in a product, an acknowledgment
11 in the product documentation would be appreciated but is not required.
12
13 2. Altered source versions must be plainly marked as such, and must not be misrepresented
14 as being the original software.
15
16 3. This notice may not be removed or altered from any source distribution.
diff --git a/raylib/src/Makefile b/raylib/src/Makefile
new file mode 100644
index 0000000..7dde52f
--- /dev/null
+++ b/raylib/src/Makefile
@@ -0,0 +1,873 @@
1#******************************************************************************
2#
3# raylib makefile
4#
5# This file supports building raylib library for the following platforms:
6#
7# > PLATFORM_DESKTOP
8# - Defaults to PLATFORM_DESKTOP_GLFW
9# > PLATFORM_DESKTOP_GLFW (GLFW backend):
10# - Windows (Win32, Win64)
11# - Linux (X11/Wayland desktop mode)
12# - macOS/OSX (x64, arm64)
13# - FreeBSD, OpenBSD, NetBSD, DragonFly (X11 desktop)
14# > PLATFORM_DESKTOP_SDL (SDL backend):
15# - Windows (Win32, Win64)
16# - Linux (X11/Wayland desktop mode)
17# - Others (not tested)
18# > PLATFORM_DESKTOP_RGFW (RGFW backend):
19# - Windows (Win32, Win64)
20# - Linux (X11 desktop mode)
21# - macOS/OSX (x64, arm64 (not tested))
22# - Others (not tested)
23# > PLATFORM_WEB:
24# - HTML5 (WebAssembly)
25# > PLATFORM_DRM:
26# - Raspberry Pi 0-5 (DRM/KMS)
27# - Linux DRM subsystem (KMS mode)
28# > PLATFORM_ANDROID:
29# - Android (ARM, ARM64)
30#
31# Many thanks to Milan Nikolic (@gen2brain) for implementing Android platform pipeline.
32# Many thanks to Emanuele Petriglia for his contribution on GNU/Linux pipeline.
33#
34# Copyright (c) 2013-2024 Ramon Santamaria (@raysan5)
35#
36# This software is provided "as-is", without any express or implied warranty. In no event
37# will the authors be held liable for any damages arising from the use of this software.
38#
39# Permission is granted to anyone to use this software for any purpose, including commercial
40# applications, and to alter it and redistribute it freely, subject to the following restrictions:
41#
42# 1. The origin of this software must not be misrepresented; you must not claim that you
43# wrote the original software. If you use this software in a product, an acknowledgment
44# in the product documentation would be appreciated but is not required.
45#
46# 2. Altered source versions must be plainly marked as such, and must not be misrepresented
47# as being the original software.
48#
49# 3. This notice may not be removed or altered from any source distribution.
50#
51#**************************************************************************************************
52
53# NOTE: Highly recommended to read the raylib Wiki to know how to compile raylib for different platforms
54# https://github.com/raysan5/raylib/wiki
55
56.PHONY: all clean install uninstall
57
58# Define required environment variables
59#------------------------------------------------------------------------------------------------
60# Define target platform
61PLATFORM ?= PLATFORM_DESKTOP
62
63ifeq ($(PLATFORM), PLATFORM_DESKTOP)
64 TARGET_PLATFORM = PLATFORM_DESKTOP_GLFW
65else
66 TARGET_PLATFORM = $(PLATFORM)
67endif
68
69# Define required raylib variables
70RAYLIB_VERSION = 5.5.0
71RAYLIB_API_VERSION = 550
72
73# Define raylib source code path
74RAYLIB_SRC_PATH ?= ../src
75
76# Define output directory for compiled library, defaults to src directory
77# NOTE: If externally provided, make sure directory exists
78RAYLIB_RELEASE_PATH ?= $(RAYLIB_SRC_PATH)
79
80# Library type used for raylib: STATIC (.a) or SHARED (.so/.dll)
81RAYLIB_LIBTYPE ?= STATIC
82
83# Build mode for library: DEBUG or RELEASE
84RAYLIB_BUILD_MODE ?= RELEASE
85
86# Build output name for the library
87RAYLIB_LIB_NAME ?= raylib
88
89# Define resource file for DLL properties
90RAYLIB_RES_FILE ?= ./raylib.dll.rc.data
91
92# Define external config flags
93# NOTE: It will override config.h flags with the provided ones,
94# if NONE, default config.h flags are used
95RAYLIB_CONFIG_FLAGS ?= NONE
96
97# To define additional cflags: Use make CUSTOM_CFLAGS=""
98
99# Include raylib modules on compilation
100# NOTE: Some programs like tools could not require those modules
101RAYLIB_MODULE_AUDIO ?= TRUE
102RAYLIB_MODULE_MODELS ?= TRUE
103RAYLIB_MODULE_RAYGUI ?= FALSE
104
105# NOTE: Additional libraries have been moved to their own repos:
106# raygui: https://github.com/raysan5/raygui
107RAYLIB_MODULE_RAYGUI_PATH ?= $(RAYLIB_SRC_PATH)/../../raygui/src
108
109# Use external GLFW library instead of rglfw module
110USE_EXTERNAL_GLFW ?= FALSE
111
112# Enable support for X11 by default on Linux when using GLFW
113# NOTE: Wayland is disabled by default, only enable if you are sure
114GLFW_LINUX_ENABLE_WAYLAND ?= FALSE
115GLFW_LINUX_ENABLE_X11 ?= TRUE
116
117# PLATFORM_DESKTOP_SDL: It requires SDL library to be provided externally
118# WARNING: Library is not included in raylib, it MUST be configured by users
119SDL_INCLUDE_PATH ?= $(RAYLIB_SRC_PATH)/external/SDL2/include
120SDL_LIBRARY_PATH ?= $(RAYLIB_SRC_PATH)/external/SDL2/lib
121SDL_LIBRARIES ?= -lSDL2 -lSDL2main
122
123
124# Determine if the file has root access (only required to install raylib)
125# "whoami" prints the name of the user that calls him (so, if it is the root user, "whoami" prints "root")
126ROOT = $(shell whoami)
127
128# By default we suppose we are working on Windows
129HOST_PLATFORM_OS ?= WINDOWS
130PLATFORM_OS ?= WINDOWS
131
132# Determine PLATFORM_OS when required
133ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW PLATFORM_DESKTOP_SDL PLATFORM_DESKTOP_RGFW PLATFORM_WEB PLATFORM_ANDROID))
134 # No uname.exe on MinGW!, but OS=Windows_NT on Windows!
135 # ifeq ($(UNAME),Msys) -> Windows
136 ifeq ($(OS),Windows_NT)
137 PLATFORM_OS = WINDOWS
138 ifndef PLATFORM_SHELL
139 PLATFORM_SHELL = cmd
140 endif
141 else
142 UNAMEOS = $(shell uname)
143 ifeq ($(UNAMEOS),Linux)
144 PLATFORM_OS = LINUX
145 endif
146 ifeq ($(UNAMEOS),FreeBSD)
147 PLATFORM_OS = BSD
148 endif
149 ifeq ($(UNAMEOS),OpenBSD)
150 PLATFORM_OS = BSD
151 endif
152 ifeq ($(UNAMEOS),NetBSD)
153 PLATFORM_OS = BSD
154 endif
155 ifeq ($(UNAMEOS),DragonFly)
156 PLATFORM_OS = BSD
157 endif
158 ifeq ($(UNAMEOS),Darwin)
159 PLATFORM_OS = OSX
160 endif
161 ifndef PLATFORM_SHELL
162 PLATFORM_SHELL = sh
163 endif
164 endif
165endif
166ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
167 UNAMEOS = $(shell uname)
168 ifeq ($(UNAMEOS),Linux)
169 PLATFORM_OS = LINUX
170 endif
171 ifndef PLATFORM_SHELL
172 PLATFORM_SHELL = sh
173 endif
174endif
175ifeq ($(TARGET_PLATFORM),PLATFORM_WEB)
176 ifeq ($(PLATFORM_OS),LINUX)
177 ifndef PLATFORM_SHELL
178 PLATFORM_SHELL = sh
179 endif
180 endif
181endif
182
183ifeq ($(TARGET_PLATFORM),PLATFORM_WEB)
184 ifeq ($(PLATFORM_OS), WINDOWS)
185 # Emscripten required variables
186 EMSDK_PATH ?= C:/raylib/emsdk
187 EMSCRIPTEN_PATH ?= $(EMSDK_PATH)/upstream/emscripten
188 CLANG_PATH := $(EMSDK_PATH)/upstream/bin
189 PYTHON_PATH := $(EMSDK_PATH)/python/3.9.2-nuget_64bit
190 NODE_PATH := $(EMSDK_PATH)/node/20.18.0_64bit/bin
191 export PATH := $(EMSDK_PATH);$(EMSCRIPTEN_PATH);$(CLANG_PATH);$(NODE_PATH);$(PYTHON_PATH);C:/raylib/MinGW/bin;$(PATH)
192 endif
193endif
194
195ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
196 # Android architecture
197 # Starting at 2019 using arm64 is mandatory for published apps,
198 # Starting on August 2020, minimum required target API is Android 10 (API level 29)
199 ANDROID_ARCH ?= arm64
200 ANDROID_API_VERSION ?= 29
201
202 # Android required path variables
203 # NOTE: Starting with Android NDK r21, no more toolchain generation is required, NDK is the toolchain on itself
204 ifeq ($(OS),Windows_NT)
205 ANDROID_NDK ?= C:/android-ndk
206 ANDROID_TOOLCHAIN = $(ANDROID_NDK)/toolchains/llvm/prebuilt/windows-x86_64
207 else
208 ANDROID_NDK ?= /usr/lib/android/ndk
209 ifeq ($(PLATFORM_OS), OSX)
210 ANDROID_TOOLCHAIN = $(ANDROID_NDK)/toolchains/llvm/prebuilt/darwin-x86_64
211 else
212 ANDROID_TOOLCHAIN = $(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64
213 endif
214 endif
215
216 # NOTE: Sysroot can also be reference from $(ANDROID_NDK)/sysroot
217 ANDROID_SYSROOT ?= $(ANDROID_TOOLCHAIN)/sysroot
218
219 ifeq ($(ANDROID_ARCH),arm)
220 ANDROID_COMPILER_ARCH = armv7a
221 endif
222 ifeq ($(ANDROID_ARCH),arm64)
223 ANDROID_COMPILER_ARCH = aarch64
224 endif
225 ifeq ($(ANDROID_ARCH),x86)
226 ANDROID_COMPILER_ARCH = i686
227 endif
228 ifeq ($(ANDROID_ARCH),x86_64)
229 ANDROID_COMPILER_ARCH = x86_64
230 endif
231
232endif
233
234# Define raylib graphics api depending on selected platform
235# NOTE: By default use OpenGL 3.3 on desktop platforms
236ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
237 GRAPHICS ?= GRAPHICS_API_OPENGL_33
238 #GRAPHICS = GRAPHICS_API_OPENGL_11 # Uncomment to use OpenGL 1.1
239 #GRAPHICS = GRAPHICS_API_OPENGL_21 # Uncomment to use OpenGL 2.1
240 #GRAPHICS = GRAPHICS_API_OPENGL_43 # Uncomment to use OpenGL 4.3
241 #GRAPHICS = GRAPHICS_API_OPENGL_ES2 # Uncomment to use OpenGL ES 2.0 (ANGLE)
242endif
243ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_SDL)
244 GRAPHICS ?= GRAPHICS_API_OPENGL_33
245endif
246ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_RGFW)
247 GRAPHICS ?= GRAPHICS_API_OPENGL_33
248 #GRAPHICS = GRAPHICS_API_OPENGL_11 # Uncomment to use OpenGL 1.1
249 #GRAPHICS = GRAPHICS_API_OPENGL_21 # Uncomment to use OpenGL 2.1
250 #GRAPHICS = GRAPHICS_API_OPENGL_43 # Uncomment to use OpenGL 4.3
251 #GRAPHICS = GRAPHICS_API_OPENGL_ES2 # Uncomment to use OpenGL ES 2.0 (ANGLE)
252endif
253ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
254 # On DRM OpenGL ES 2.0 must be used
255 GRAPHICS = GRAPHICS_API_OPENGL_ES2
256endif
257ifeq ($(TARGET_PLATFORM),PLATFORM_WEB)
258 # On HTML5 OpenGL ES 2.0 is used, emscripten translates it to WebGL 1.0
259 GRAPHICS = GRAPHICS_API_OPENGL_ES2
260 #GRAPHICS = GRAPHICS_API_OPENGL_ES3
261endif
262ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
263 # By default use OpenGL ES 2.0 on Android
264 GRAPHICS = GRAPHICS_API_OPENGL_ES2
265endif
266
267# Define default C compiler and archiver to pack library: CC, AR
268#------------------------------------------------------------------------------------------------
269CC = gcc
270AR = ar
271
272ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
273 ifeq ($(PLATFORM_OS),OSX)
274 # OSX default compiler
275 CC = clang
276 GLFW_OSX = -x objective-c
277 endif
278 ifeq ($(PLATFORM_OS),BSD)
279 # FreeBSD, OpenBSD, NetBSD, DragonFly default compiler
280 CC = clang
281 endif
282endif
283ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
284 ifeq ($(USE_RPI_CROSS_COMPILER),TRUE)
285 # Define RPI cross-compiler
286 #CC = armv6j-hardfloat-linux-gnueabi-gcc
287 CC = $(RPI_TOOLCHAIN)/bin/$(RPI_TOOLCHAIN_NAME)-gcc
288 AR = $(RPI_TOOLCHAIN)/bin/$(RPI_TOOLCHAIN_NAME)-ar
289 endif
290endif
291ifeq ($(TARGET_PLATFORM),PLATFORM_WEB)
292 # HTML5 emscripten compiler
293 CC = emcc
294 AR = emar
295endif
296ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
297 # Android toolchain (must be provided for desired architecture and compiler)
298 ifeq ($(ANDROID_ARCH),arm)
299 CC = $(ANDROID_TOOLCHAIN)/bin/$(ANDROID_COMPILER_ARCH)-linux-androideabi$(ANDROID_API_VERSION)-clang
300 endif
301 ifeq ($(ANDROID_ARCH),arm64)
302 CC = $(ANDROID_TOOLCHAIN)/bin/$(ANDROID_COMPILER_ARCH)-linux-android$(ANDROID_API_VERSION)-clang
303 endif
304 ifeq ($(ANDROID_ARCH),x86)
305 CC = $(ANDROID_TOOLCHAIN)/bin/$(ANDROID_COMPILER_ARCH)-linux-android$(ANDROID_API_VERSION)-clang
306 endif
307 ifeq ($(ANDROID_ARCH),x86_64)
308 CC = $(ANDROID_TOOLCHAIN)/bin/$(ANDROID_COMPILER_ARCH)-linux-android$(ANDROID_API_VERSION)-clang
309 endif
310 # It seems from Android NDK r22 onwards we need to use llvm-ar
311 AR = $(ANDROID_TOOLCHAIN)/bin/llvm-ar
312endif
313
314# Define compiler flags: CFLAGS
315#------------------------------------------------------------------------------------------------
316# -O1 defines optimization level
317# -g include debug information on compilation
318# -s strip unnecessary data from build --> linker
319# -Wall turns on most, but not all, compiler warnings
320# -std=c99 defines C language mode (standard C from 1999 revision)
321# -std=gnu99 defines C language mode (GNU C from 1999 revision)
322# -Wno-missing-braces ignore invalid warning (GCC bug 53119)
323# -Wno-unused-value ignore unused return values of some functions (i.e. fread())
324# -D_DEFAULT_SOURCE use with -std=c99 on Linux and PLATFORM_WEB, required for timespec
325# -D_GNU_SOURCE access to lots of nonstandard GNU/Linux extension functions
326# -Werror=pointer-arith catch unportable code that does direct arithmetic on void pointers
327# -fno-strict-aliasing jar_xm.h does shady stuff (breaks strict aliasing)
328CFLAGS = -Wall -D_GNU_SOURCE -D$(TARGET_PLATFORM) -D$(GRAPHICS) -Wno-missing-braces -Werror=pointer-arith -fno-strict-aliasing
329
330ifneq ($(RAYLIB_CONFIG_FLAGS), NONE)
331 CFLAGS += -DEXTERNAL_CONFIG_FLAGS $(RAYLIB_CONFIG_FLAGS)
332endif
333
334ifeq ($(TARGET_PLATFORM), PLATFORM_WEB)
335 # NOTE: When using multi-threading in the user code, it requires -pthread enabled
336 CFLAGS += -std=gnu99
337else
338 CFLAGS += -std=c99
339endif
340
341ifeq ($(PLATFORM_OS), LINUX)
342 CFLAGS += -fPIC
343endif
344
345ifeq ($(RAYLIB_BUILD_MODE),DEBUG)
346 CFLAGS += -g -D_DEBUG
347endif
348
349ifeq ($(RAYLIB_BUILD_MODE),RELEASE)
350 ifeq ($(TARGET_PLATFORM),PLATFORM_WEB)
351 CFLAGS += -Os
352 endif
353 ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
354 CFLAGS += -O1
355 endif
356 ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
357 CFLAGS += -O2
358 endif
359endif
360
361# Additional flags for compiler (if desired)
362# -Wextra enables some extra warning flags that are not enabled by -Wall
363# -Wmissing-prototypes warn if a global function is defined without a previous prototype declaration
364# -Wstrict-prototypes warn if a function is declared or defined without specifying the argument types
365# -Werror=implicit-function-declaration catch function calls without prior declaration
366ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
367 CFLAGS += -Werror=implicit-function-declaration
368endif
369ifeq ($(TARGET_PLATFORM),PLATFORM_WEB)
370 # -Os # size optimization
371 # -O2 # optimization level 2, if used, also set --memory-init-file 0
372 # -sUSE_GLFW=3 # Use glfw3 library (context/input management) -> Only for linker!
373 # -sALLOW_MEMORY_GROWTH=1 # to allow memory resizing -> WARNING: Audio buffers could FAIL!
374 # -sTOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB)
375 # -sUSE_PTHREADS=1 # multithreading support
376 # -sFORCE_FILESYSTEM=1 # force filesystem to load/save files data
377 # -sASSERTIONS=1 # enable runtime checks for common memory allocation errors (-O1 and above turn it off)
378 # -sGL_ENABLE_GET_PROC_ADDRESS # enable using the *glGetProcAddress() family of functions, required for extensions loading
379 # --profiling # include information for code profiling
380 # --memory-init-file 0 # to avoid an external memory initialization code file (.mem)
381 # --preload-file resources # specify a resources folder for data compilation
382 ifeq ($(RAYLIB_BUILD_MODE),DEBUG)
383 CFLAGS += -sASSERTIONS=1 --profiling
384 endif
385 #CFLAGS += -sGL_ENABLE_GET_PROC_ADDRESS
386endif
387ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
388 # Compiler flags for arquitecture
389 ifeq ($(ANDROID_ARCH),arm)
390 CFLAGS += -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16
391 endif
392 ifeq ($(ANDROID_ARCH),arm64)
393 CFLAGS += -target aarch64 -mfix-cortex-a53-835769
394 endif
395 ifeq ($(ANDROID_ARCH),x86)
396 CFLAGS += -march=i686
397 endif
398 ifeq ($(ANDROID_ARCH),x86_64)
399 CFLAGS += -march=x86-64
400 endif
401 # Compilation functions attributes options
402 CFLAGS += -ffunction-sections -funwind-tables -fstack-protector-strong -fPIE -fPIC
403 # Compiler options for the linker
404 # -Werror=format-security
405 CFLAGS += -Wa,--noexecstack -Wformat -no-canonical-prefixes
406 # Preprocessor macro definitions
407 CFLAGS += -D__ANDROID__ -DPLATFORM_ANDROID -D__ANDROID_API__=$(ANDROID_API_VERSION)
408endif
409
410# Define required compilation flags for raylib SHARED lib
411ifeq ($(RAYLIB_LIBTYPE),SHARED)
412 # make sure code is compiled as position independent
413 # BE CAREFUL: It seems that for gcc -fpic is not the same as -fPIC
414 # MinGW32 just doesn't need -fPIC, it shows warnings
415 CFLAGS += -fPIC -DBUILD_LIBTYPE_SHARED
416
417 # hide all symbols by default, so RLAPI can expose them
418 ifeq ($(PLATFORM_OS),$(filter $(PLATFORM_OS), LINUX BSD OSX))
419 CFLAGS += -fvisibility=hidden
420 endif
421endif
422
423ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
424 # without EGL_NO_X11 eglplatform.h tears Xlib.h in which tears X.h in
425 # which contains a conflicting type Font
426 CFLAGS += -DEGL_NO_X11
427 CFLAGS += -Werror=implicit-function-declaration
428endif
429# Use Wayland display on Linux desktop
430ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
431 ifeq ($(PLATFORM_OS), LINUX)
432 ifeq ($(GLFW_LINUX_ENABLE_X11),TRUE)
433 CFLAGS += -D_GLFW_X11
434 endif
435 ifeq ($(GLFW_LINUX_ENABLE_WAYLAND),TRUE)
436 CFLAGS += -D_GLFW_WAYLAND
437 LDFLAGS += $(shell pkg-config wayland-client wayland-cursor wayland-egl xkbcommon --libs)
438
439 WL_PROTOCOLS_DIR := external/glfw/deps/wayland
440
441 wl_generate = \
442 $(eval protocol=$(1)) \
443 $(eval basename=$(2)) \
444 $(shell wayland-scanner client-header $(protocol) $(RAYLIB_SRC_PATH)/$(basename).h) \
445 $(shell wayland-scanner private-code $(protocol) $(RAYLIB_SRC_PATH)/$(basename)-code.h)
446
447 $(call wl_generate, $(WL_PROTOCOLS_DIR)/wayland.xml, wayland-client-protocol)
448 $(call wl_generate, $(WL_PROTOCOLS_DIR)/xdg-shell.xml, xdg-shell-client-protocol)
449 $(call wl_generate, $(WL_PROTOCOLS_DIR)/xdg-decoration-unstable-v1.xml, xdg-decoration-unstable-v1-client-protocol)
450 $(call wl_generate, $(WL_PROTOCOLS_DIR)/viewporter.xml, viewporter-client-protocol)
451 $(call wl_generate, $(WL_PROTOCOLS_DIR)/relative-pointer-unstable-v1.xml, relative-pointer-unstable-v1-client-protocol)
452 $(call wl_generate, $(WL_PROTOCOLS_DIR)/pointer-constraints-unstable-v1.xml, pointer-constraints-unstable-v1-client-protocol)
453 $(call wl_generate, $(WL_PROTOCOLS_DIR)/fractional-scale-v1.xml, fractional-scale-v1-client-protocol)
454 $(call wl_generate, $(WL_PROTOCOLS_DIR)/xdg-activation-v1.xml, xdg-activation-v1-client-protocol)
455 $(call wl_generate, $(WL_PROTOCOLS_DIR)/idle-inhibit-unstable-v1.xml, idle-inhibit-unstable-v1-client-protocol)
456 endif
457 endif
458endif
459
460CFLAGS += $(CUSTOM_CFLAGS)
461
462# Define include paths for required headers: INCLUDE_PATHS
463# NOTE: Several external required libraries (stb and others)
464#------------------------------------------------------------------------------------------------
465INCLUDE_PATHS = -I. $(EXTRA_INCLUDE_PATHS)
466
467# Define additional directories containing required header files
468ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
469 INCLUDE_PATHS += -Iexternal/glfw/include
470 ifeq ($(PLATFORM_OS),BSD)
471 INCLUDE_PATHS += -I/usr/local/include -I/usr/pkg/include -I/usr/X11R7/include
472 endif
473endif
474ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_SDL)
475 INCLUDE_PATHS += -I$(SDL_INCLUDE_PATH)
476endif
477ifeq ($(TARGET_PLATFORM),PLATFORM_WEB)
478 INCLUDE_PATHS += -Iexternal/glfw/include
479endif
480ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
481 INCLUDE_PATHS += -I/usr/include/libdrm
482 ifeq ($(USE_RPI_CROSSCOMPILER), TRUE)
483 INCLUDE_PATHS += -I$(RPI_TOOLCHAIN_SYSROOT)/usr/include
484 INCLUDE_PATHS += -I$(RPI_TOOLCHAIN_SYSROOT)/opt/vc/include
485 endif
486endif
487ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
488 NATIVE_APP_GLUE = $(ANDROID_NDK)/sources/android/native_app_glue
489 # Include android_native_app_glue.h
490 INCLUDE_PATHS += -I$(NATIVE_APP_GLUE)
491
492 # Android required libraries
493 INCLUDE_PATHS += -I$(ANDROID_SYSROOT)/usr/include
494 ifeq ($(ANDROID_ARCH),arm)
495 INCLUDE_PATHS += -I$(ANDROID_SYSROOT)/usr/include/arm-linux-androideabi
496 endif
497 ifeq ($(ANDROID_ARCH),arm64)
498 INCLUDE_PATHS += -I$(ANDROID_SYSROOT)/usr/include/aarch64-linux-android
499 endif
500 ifeq ($(ANDROID_ARCH),x86)
501 INCLUDE_PATHS += -I$(ANDROID_SYSROOT)/usr/include/i686-linux-android
502 endif
503 ifeq ($(ANDROID_ARCH),x86_64)
504 INCLUDE_PATHS += -I$(ANDROID_SYSROOT)/usr/include/x86_64-linux-android
505 endif
506endif
507
508# Define library paths containing required libs: LDFLAGS
509# NOTE: This is only required for dynamic library generation
510#------------------------------------------------------------------------------------------------
511LDFLAGS = $(CUSTOM_LDFLAGS) -L. -L$(RAYLIB_RELEASE_PATH)
512
513ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
514 ifeq ($(PLATFORM_OS),WINDOWS)
515 ifneq ($(CC), tcc)
516 LDFLAGS += -Wl,--out-implib,$(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME)dll.a
517 endif
518 endif
519 ifeq ($(PLATFORM_OS),OSX)
520 LDFLAGS += -compatibility_version $(RAYLIB_API_VERSION) -current_version $(RAYLIB_VERSION)
521 endif
522 ifeq ($(PLATFORM_OS),LINUX)
523 LDFLAGS += -Wl,-soname,lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_API_VERSION)
524 endif
525 ifeq ($(PLATFORM_OS),BSD)
526 LDFLAGS += -Wl,-soname,lib$(RAYLIB_LIB_NAME).$(RAYLIB_API_VERSION).so -Lsrc -L/usr/local/lib -L/usr/pkg/lib -Wl,-R/usr/pkg/lib
527 endif
528endif
529ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_SDL)
530 LDFLAGS += -Wl,-soname,lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_API_VERSION)
531 LDFLAGS += -L$(SDL_LIBRARY_PATH)
532endif
533ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
534 LDFLAGS += -Wl,-soname,lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_API_VERSION)
535 ifeq ($(USE_RPI_CROSSCOMPILER), TRUE)
536 LDFLAGS += -L$(RPI_TOOLCHAIN_SYSROOT)/opt/vc/lib -L$(RPI_TOOLCHAIN_SYSROOT)/usr/lib
537 endif
538endif
539ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
540 LDFLAGS += -Wl,-soname,libraylib.$(RAYLIB_API_VERSION).so -Wl,--exclude-libs,libatomic.a
541 LDFLAGS += -Wl,--build-id -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel -Wl,--fatal-warnings
542 # Force linking of library module to define symbol
543 LDFLAGS += -u ANativeActivity_onCreate
544 # Library paths containing required libs
545 LDFLAGS += -Lsrc
546 # Avoid unresolved symbol pointing to external main()
547 LDFLAGS += -Wl,-undefined,dynamic_lookup
548endif
549
550# Define libraries required on linking: LDLIBS
551# NOTE: This is only required for dynamic library generation
552#------------------------------------------------------------------------------------------------
553ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
554 ifeq ($(PLATFORM_OS),WINDOWS)
555 ifeq ($(CC), tcc)
556 LDLIBS = -lopengl32 -lgdi32 -lwinmm -lshell32
557 else
558 LDLIBS = -static-libgcc -lopengl32 -lgdi32 -lwinmm
559 endif
560 endif
561 ifeq ($(PLATFORM_OS),LINUX)
562 LDLIBS = -lGL -lc -lm -lpthread -ldl -lrt
563 ifeq ($(GLFW_LINUX_ENABLE_X11),TRUE)
564 LDLIBS += -lX11
565 endif
566 # TODO: On ARM 32bit arch, miniaudio requires atomics library
567 #LDLIBS += -latomic
568 endif
569 ifeq ($(PLATFORM_OS),OSX)
570 LDLIBS = -framework OpenGL -framework Cocoa -framework IOKit -framework CoreAudio -framework CoreVideo
571 endif
572 ifeq ($(PLATFORM_OS),BSD)
573 LDLIBS = -lGL -lpthread
574 endif
575 ifeq ($(USE_EXTERNAL_GLFW),TRUE)
576 # Check the version name. If GLFW3 was built manually, it may have produced
577 # a static library known as libglfw3.a. In that case, the name should be -lglfw3
578 LDLIBS = -lglfw
579 endif
580endif
581ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_SDL)
582 ifeq ($(PLATFORM_OS),WINDOWS)
583 LDLIBS = -static-libgcc -lopengl32 -lgdi32
584 endif
585 ifeq ($(PLATFORM_OS),LINUX)
586 LDLIBS = -lGL -lc -lm -lpthread -ldl -lrt
587 ifeq ($(USE_WAYLAND_DISPLAY),FALSE)
588 LDLIBS += -lX11
589 endif
590 endif
591 LDLIBS += $(SDL_LIBRARIES)
592endif
593ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_RGFW)
594 ifeq ($(PLATFORM_OS),WINDOWS)
595 # Libraries for Windows desktop compilation
596 LDLIBS = -lgdi32 -lwinmm -lopengl32
597 endif
598 ifeq ($(PLATFORM_OS),LINUX)
599 # Libraries for Debian GNU/Linux desktop compipling
600 # NOTE: Required packages: libegl1-mesa-dev
601 LDLIBS = -lGL -lX11 -lXrandr -lXinerama -lXi -lXcursor -lm -lpthread -ldl -lrt
602
603 # Explicit link to libc
604 ifeq ($(RAYLIB_LIBTYPE),SHARED)
605 LDLIBS += -lc
606 endif
607
608 # NOTE: On ARM 32bit arch, miniaudio requires atomics library
609 LDLIBS += -latomic
610 endif
611 ifeq ($(PLATFORM_OS),OSX)
612 # Libraries for Debian MacOS desktop compiling
613 # NOTE: Required packages: libegl1-mesa-dev
614 LDLIBS += -lm -framework Foundation -framework AppKit -framework OpenGL -framework CoreVideo
615 endif
616endif
617ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
618 LDLIBS = -lGLESv2 -lEGL -ldrm -lgbm -lpthread -lrt -lm -ldl
619 ifeq ($(RAYLIB_MODULE_AUDIO),TRUE)
620 LDLIBS += -latomic
621 endif
622endif
623ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
624 LDLIBS = -llog -landroid -lEGL -lGLESv2 -lOpenSLES -lc -lm
625endif
626
627# Define source code object files required
628#------------------------------------------------------------------------------------------------
629OBJS = rcore.o \
630 rshapes.o \
631 rtextures.o \
632 rtext.o \
633 utils.o
634
635ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
636 ifeq ($(USE_EXTERNAL_GLFW),FALSE)
637 OBJS += rglfw.o
638 endif
639endif
640ifeq ($(RAYLIB_MODULE_MODELS),TRUE)
641 OBJS += rmodels.o
642endif
643ifeq ($(RAYLIB_MODULE_AUDIO),TRUE)
644 OBJS += raudio.o
645endif
646ifeq ($(RAYLIB_MODULE_RAYGUI),TRUE)
647 OBJS += raygui.o
648endif
649
650ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
651 OBJS += android_native_app_glue.o
652endif
653
654# Define processes to execute
655#------------------------------------------------------------------------------------------------
656# Default target entry
657all: raylib
658
659# Compile raylib library
660# NOTE: Release directory is created if not exist
661raylib: $(OBJS)
662ifeq ($(TARGET_PLATFORM),PLATFORM_WEB)
663 # Compile raylib libray for web
664 #$(CC) $(OBJS) -r -o $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).bc
665 $(AR) rcs $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).a $(OBJS)
666 @echo "raylib library generated (lib$(RAYLIB_LIB_NAME).a)!"
667else
668 ifeq ($(RAYLIB_LIBTYPE),SHARED)
669 ifeq ($(TARGET_PLATFORM),$(filter $(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW PLATFORM_DESKTOP_SDL PLATFORM_DESKTOP_RGFW))
670 ifeq ($(PLATFORM_OS),WINDOWS)
671 # NOTE: Linking with provided resource file
672 $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/$(RAYLIB_LIB_NAME).dll $(OBJS) $(RAYLIB_RES_FILE) $(LDFLAGS) $(LDLIBS)
673 @echo "raylib dynamic library ($(RAYLIB_LIB_NAME).dll) and import library (lib$(RAYLIB_LIB_NAME)dll.a) generated!"
674 endif
675 ifeq ($(PLATFORM_OS),LINUX)
676 # Compile raylib shared library version $(RAYLIB_VERSION).
677 # WARNING: you should type "make clean" before doing this target
678 $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_VERSION) $(OBJS) $(LDFLAGS) $(LDLIBS)
679 @echo "raylib shared library generated (lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_VERSION)) in $(RAYLIB_RELEASE_PATH)!"
680 cd $(RAYLIB_RELEASE_PATH) && ln -fsv lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_VERSION) lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_API_VERSION)
681 cd $(RAYLIB_RELEASE_PATH) && ln -fsv lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_API_VERSION) lib$(RAYLIB_LIB_NAME).so
682 endif
683 ifeq ($(PLATFORM_OS),OSX)
684 $(CC) -dynamiclib -o $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).dylib $(OBJS) $(LDFLAGS) $(LDLIBS)
685 install_name_tool -id "@rpath/lib$(RAYLIB_LIB_NAME).$(RAYLIB_API_VERSION).dylib" $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).dylib
686 @echo "raylib shared library generated (lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).dylib)!"
687 cd $(RAYLIB_RELEASE_PATH) && ln -fs lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).dylib lib$(RAYLIB_LIB_NAME).$(RAYLIB_API_VERSION).dylib
688 cd $(RAYLIB_RELEASE_PATH) && ln -fs lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).dylib lib$(RAYLIB_LIB_NAME).dylib
689 endif
690 ifeq ($(PLATFORM_OS),BSD)
691 # WARNING: you should type "gmake clean" before doing this target
692 $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).so $(OBJS) $(LDFLAGS) $(LDLIBS)
693 @echo "raylib shared library generated (lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).so)!"
694 cd $(RAYLIB_RELEASE_PATH) && ln -fs lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).so lib$(RAYLIB_LIB_NAME).$(RAYLIB_API_VERSION).so
695 cd $(RAYLIB_RELEASE_PATH) && ln -fs lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).so lib$(RAYLIB_LIB_NAME).so
696 endif
697 endif
698 ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
699 # Compile raylib shared library version $(RAYLIB_VERSION).
700 # WARNING: you should type "make clean" before doing this target
701 $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_VERSION) $(OBJS) $(LDFLAGS) $(LDLIBS)
702 @echo "raylib shared library generated (lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_VERSION)) in $(RAYLIB_RELEASE_PATH)!"
703 cd $(RAYLIB_RELEASE_PATH) && ln -fsv lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_VERSION) lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_API_VERSION)
704 cd $(RAYLIB_RELEASE_PATH) && ln -fsv lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_API_VERSION) lib$(RAYLIB_LIB_NAME).so
705 endif
706 ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
707 $(CC) -shared -o $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).so $(OBJS) $(LDFLAGS) $(LDLIBS)
708 @echo "raylib shared library generated (lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).so)!"
709 # WARNING: symbolic links creation on Windows should be done using mklink command, no ln available
710 ifeq ($(HOST_PLATFORM_OS),LINUX)
711 cd $(RAYLIB_RELEASE_PATH) && ln -fs lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).so lib$(RAYLIB_LIB_NAME).$(RAYLIB_API_VERSION).so
712 cd $(RAYLIB_RELEASE_PATH) && ln -fs lib$(RAYLIB_LIB_NAME).$(RAYLIB_VERSION).so lib$(RAYLIB_LIB_NAME).so
713 endif
714 endif
715 else
716 # Compile raylib static library version $(RAYLIB_VERSION)
717 # WARNING: You should type "make clean" before doing this target.
718 $(AR) rcs $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).a $(OBJS)
719 @echo "raylib static library generated (lib$(RAYLIB_LIB_NAME).a) in $(RAYLIB_RELEASE_PATH)!"
720 endif
721endif
722
723# Compile all modules with their prerequisites
724
725# Prerequisites of core module
726rcore.o : platforms/*.c
727
728# Compile core module
729rcore.o : rcore.c raylib.h rlgl.h utils.h raymath.h rcamera.h rgestures.h
730 $(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS)
731
732# Compile rglfw module
733rglfw.o : rglfw.c
734 $(CC) $(GLFW_OSX) -c $< $(CFLAGS) $(INCLUDE_PATHS)
735
736# Compile shapes module
737rshapes.o : rshapes.c raylib.h rlgl.h
738 $(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS)
739
740# Compile textures module
741rtextures.o : rtextures.c raylib.h rlgl.h utils.h
742 $(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS)
743
744# Compile text module
745rtext.o : rtext.c raylib.h utils.h
746 $(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS)
747
748# Compile utils module
749utils.o : utils.c utils.h
750 $(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS)
751
752# Compile models module
753rmodels.o : rmodels.c raylib.h rlgl.h raymath.h
754 $(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS)
755
756# Compile audio module
757raudio.o : raudio.c raylib.h
758 $(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS)
759
760# Compile raygui module
761# NOTE: raygui header should be distributed with raylib.h
762raygui.o : raygui.c
763 $(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS)
764raygui.c:
765ifeq ($(PLATFORM_SHELL), cmd)
766 @echo #define RAYGUI_IMPLEMENTATION > raygui.c
767 @echo #include "$(RAYLIB_MODULE_RAYGUI_PATH)/raygui.h" >> raygui.c
768else
769 @echo "#define RAYGUI_IMPLEMENTATION" > raygui.c
770 @echo "#include \"$(RAYLIB_MODULE_RAYGUI_PATH)/raygui.h\"" >> raygui.c
771endif
772
773# Compile android_native_app_glue module
774android_native_app_glue.o : $(NATIVE_APP_GLUE)/android_native_app_glue.c
775 $(CC) -c $< $(CFLAGS) $(INCLUDE_PATHS)
776
777# Install generated and needed files to desired directories.
778# On GNU/Linux and BSDs, there are some standard directories that contain extra
779# libraries and header files. These directories (often /usr/local/lib and
780# /usr/local/include) are for libraries that are installed manually
781# (without a package manager). We'll use /usr/local/lib/raysan5 and /usr/local/include/raysan5
782# for our -L and -I specification to simplify management of the raylib source package.
783# Customize these locations if you like but don't forget to pass them to make
784# for compilation and enable runtime linking with -rpath, LD_LIBRARY_PATH, or ldconfig.
785# HINT: Add -L$(RAYLIB_INSTALL_PATH) -I$(RAYLIB_H_INSTALL_PATH) to your own makefiles.
786# See below and ../examples/Makefile for more information.
787
788# RAYLIB_INSTALL_PATH should be the desired full path to libraylib. No relative paths.
789DESTDIR ?= /usr/local
790RAYLIB_INSTALL_PATH ?= $(DESTDIR)/lib
791# RAYLIB_H_INSTALL_PATH locates the installed raylib header and associated source files.
792RAYLIB_H_INSTALL_PATH ?= $(DESTDIR)/include
793
794install :
795ifeq ($(ROOT),root)
796 ifeq ($(PLATFORM_OS),LINUX)
797 # Attention! You are root, writing files to $(RAYLIB_INSTALL_PATH)
798 # and $(RAYLIB_H_INSTALL_PATH). Consult this Makefile for more information.
799 # Prepare the environment as needed.
800 mkdir --parents --verbose $(RAYLIB_INSTALL_PATH)
801 mkdir --parents --verbose $(RAYLIB_H_INSTALL_PATH)
802 ifeq ($(RAYLIB_LIBTYPE),SHARED)
803 # Installing raylib to $(RAYLIB_INSTALL_PATH).
804 cp --update --verbose $(RAYLIB_RELEASE_PATH)/libraylib.so.$(RAYLIB_VERSION) $(RAYLIB_INSTALL_PATH)/lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_VERSION)
805 cd $(RAYLIB_INSTALL_PATH); ln -fsv lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_VERSION) lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_API_VERSION)
806 cd $(RAYLIB_INSTALL_PATH); ln -fsv lib$(RAYLIB_LIB_NAME).so.$(RAYLIB_API_VERSION) lib$(RAYLIB_LIB_NAME).so
807 # Uncomment to update the runtime linker cache with RAYLIB_INSTALL_PATH.
808 # Not necessary if later embedding RPATH in your executable. See examples/Makefile.
809 ldconfig $(RAYLIB_INSTALL_PATH)
810 else
811 # Installing raylib to $(RAYLIB_INSTALL_PATH).
812 cp --update --verbose $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).a $(RAYLIB_INSTALL_PATH)/lib$(RAYLIB_LIB_NAME).a
813 endif
814 # Copying raylib development files to $(RAYLIB_H_INSTALL_PATH).
815 cp --update raylib.h $(RAYLIB_H_INSTALL_PATH)/raylib.h
816 cp --update raymath.h $(RAYLIB_H_INSTALL_PATH)/raymath.h
817 cp --update rlgl.h $(RAYLIB_H_INSTALL_PATH)/rlgl.h
818 @echo "raylib development files installed/updated!"
819 else
820 @echo "This function currently works on GNU/Linux systems. Add yours today (^;"
821 endif
822else
823 @echo "Error: Root permissions needed for installation. Try sudo make install"
824endif
825
826# Remove raylib dev files installed on the system
827# NOTE: see 'install' target.
828uninstall :
829ifeq ($(ROOT),root)
830 # WARNING: You are root, about to delete items from $(RAYLIB_INSTALL_PATH).
831 # and $(RAYLIB_H_INSTALL_PATH). Please confirm each item.
832 ifeq ($(PLATFORM_OS),LINUX)
833 ifeq ($(RAYLIB_LIBTYPE),SHARED)
834 rm --force --interactive --verbose $(RAYLIB_INSTALL_PATH)/libraylib.so
835 rm --force --interactive --verbose $(RAYLIB_INSTALL_PATH)/libraylib.so.$(RAYLIB_API_VERSION)
836 rm --force --interactive --verbose $(RAYLIB_INSTALL_PATH)/libraylib.so.$(RAYLIB_VERSION)
837 # Uncomment to clean up the runtime linker cache. See install target.
838 ldconfig
839 else
840 rm --force --interactive --verbose $(RAYLIB_INSTALL_PATH)/libraylib.a
841 endif
842 rm --force --interactive --verbose $(RAYLIB_H_INSTALL_PATH)/raylib.h
843 rm --force --interactive --verbose $(RAYLIB_H_INSTALL_PATH)/raymath.h
844 rm --force --interactive --verbose $(RAYLIB_H_INSTALL_PATH)/rlgl.h
845 @echo "raylib development files removed!"
846 else
847 @echo "This function currently works on GNU/Linux systems. Add yours today (^;"
848 endif
849else
850 @echo "Error: Root permissions needed for uninstallation. Try sudo make uninstall"
851endif
852
853.PHONY: clean_shell_cmd clean_shell_sh
854
855# Clean everything
856clean: clean_shell_$(PLATFORM_SHELL)
857 @echo "removed all generated files!"
858
859clean_shell_sh:
860 rm -fv *.o $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).a $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).bc $(RAYLIB_RELEASE_PATH)/lib$(RAYLIB_LIB_NAME).so* raygui.c $(RAYLIB_RELEASE_PATH)/*-protocol.h $(RAYLIB_RELEASE_PATH)/*-protocol-code.h
861ifeq ($(TARGET_PLATFORM),PLATFORM_ANDROID)
862 rm -fv $(NATIVE_APP_GLUE)/android_native_app_glue.o
863endif
864
865# Set specific target variable
866clean_shell_cmd: SHELL=cmd
867clean_shell_cmd:
868 del *.o /s
869 cd $(RAYLIB_RELEASE_PATH) & \
870 del lib$(RAYLIB_LIB_NAME).a /s & \
871 del lib$(RAYLIB_LIB_NAME)dll.a /s & \
872 del $(RAYLIB_LIB_NAME).dll /s & \
873 del raygui.c /s & \
diff --git a/raylib/src/config.h b/raylib/src/config.h
new file mode 100644
index 0000000..e3749c5
--- /dev/null
+++ b/raylib/src/config.h
@@ -0,0 +1,303 @@
1/**********************************************************************************************
2*
3* raylib configuration flags
4*
5* This file defines all the configuration flags for the different raylib modules
6*
7* LICENSE: zlib/libpng
8*
9* Copyright (c) 2018-2024 Ahmad Fatoum & Ramon Santamaria (@raysan5)
10*
11* This software is provided "as-is", without any express or implied warranty. In no event
12* will the authors be held liable for any damages arising from the use of this software.
13*
14* Permission is granted to anyone to use this software for any purpose, including commercial
15* applications, and to alter it and redistribute it freely, subject to the following restrictions:
16*
17* 1. The origin of this software must not be misrepresented; you must not claim that you
18* wrote the original software. If you use this software in a product, an acknowledgment
19* in the product documentation would be appreciated but is not required.
20*
21* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
22* as being the original software.
23*
24* 3. This notice may not be removed or altered from any source distribution.
25*
26**********************************************************************************************/
27
28#ifndef CONFIG_H
29#define CONFIG_H
30
31//------------------------------------------------------------------------------------
32// Module selection - Some modules could be avoided
33// Mandatory modules: rcore, rlgl, utils
34//------------------------------------------------------------------------------------
35#define SUPPORT_MODULE_RSHAPES 1
36#define SUPPORT_MODULE_RTEXTURES 1
37#define SUPPORT_MODULE_RTEXT 1 // WARNING: It requires SUPPORT_MODULE_RTEXTURES to load sprite font textures
38#define SUPPORT_MODULE_RMODELS 1
39#define SUPPORT_MODULE_RAUDIO 1
40
41//------------------------------------------------------------------------------------
42// Module: rcore - Configuration Flags
43//------------------------------------------------------------------------------------
44// Camera module is included (rcamera.h) and multiple predefined cameras are available: free, 1st/3rd person, orbital
45#define SUPPORT_CAMERA_SYSTEM 1
46// Gestures module is included (rgestures.h) to support gestures detection: tap, hold, swipe, drag
47#define SUPPORT_GESTURES_SYSTEM 1
48// Include pseudo-random numbers generator (rprand.h), based on Xoshiro128** and SplitMix64
49#define SUPPORT_RPRAND_GENERATOR 1
50// Mouse gestures are directly mapped like touches and processed by gestures system
51#define SUPPORT_MOUSE_GESTURES 1
52// Reconfigure standard input to receive key inputs, works with SSH connection.
53#define SUPPORT_SSH_KEYBOARD_RPI 1
54// Setting a higher resolution can improve the accuracy of time-out intervals in wait functions.
55// However, it can also reduce overall system performance, because the thread scheduler switches tasks more often.
56#define SUPPORT_WINMM_HIGHRES_TIMER 1
57// Use busy wait loop for timing sync, if not defined, a high-resolution timer is set up and used
58//#define SUPPORT_BUSY_WAIT_LOOP 1
59// Use a partial-busy wait loop, in this case frame sleeps for most of the time, but then runs a busy loop at the end for accuracy
60#define SUPPORT_PARTIALBUSY_WAIT_LOOP 1
61// Allow automatic screen capture of current screen pressing F12, defined in KeyCallback()
62#define SUPPORT_SCREEN_CAPTURE 1
63// Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback()
64#define SUPPORT_GIF_RECORDING 1
65// Support CompressData() and DecompressData() functions
66#define SUPPORT_COMPRESSION_API 1
67// Support automatic generated events, loading and recording of those events when required
68#define SUPPORT_AUTOMATION_EVENTS 1
69// Support custom frame control, only for advanced users
70// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timing + PollInputEvents()
71// Enabling this flag allows manual control of the frame processes, use at your own risk
72//#define SUPPORT_CUSTOM_FRAME_CONTROL 1
73
74
75// rcore: Configuration values
76//------------------------------------------------------------------------------------
77#define MAX_FILEPATH_CAPACITY 8192 // Maximum file paths capacity
78#define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value)
79
80#define MAX_KEYBOARD_KEYS 512 // Maximum number of keyboard keys supported
81#define MAX_MOUSE_BUTTONS 8 // Maximum number of mouse buttons supported
82#define MAX_GAMEPADS 4 // Maximum number of gamepads supported
83#define MAX_GAMEPAD_AXIS 8 // Maximum number of axis supported (per gamepad)
84#define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad)
85#define MAX_GAMEPAD_VIBRATION_TIME 2.0f // Maximum vibration time in seconds
86#define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported
87#define MAX_KEY_PRESSED_QUEUE 16 // Maximum number of keys in the key input queue
88#define MAX_CHAR_PRESSED_QUEUE 16 // Maximum number of characters in the char input queue
89
90#define MAX_DECOMPRESSION_SIZE 64 // Max size allocated for decompression in MB
91
92#define MAX_AUTOMATION_EVENTS 16384 // Maximum number of automation events to record
93
94//------------------------------------------------------------------------------------
95// Module: rlgl - Configuration values
96//------------------------------------------------------------------------------------
97
98// Enable OpenGL Debug Context (only available on OpenGL 4.3)
99//#define RLGL_ENABLE_OPENGL_DEBUG_CONTEXT 1
100
101// Show OpenGL extensions and capabilities detailed logs on init
102//#define RLGL_SHOW_GL_DETAILS_INFO 1
103
104#define RL_SUPPORT_MESH_GPU_SKINNING 1 // GPU skinning, comment if your GPU does not support more than 8 VBOs
105
106//#define RL_DEFAULT_BATCH_BUFFER_ELEMENTS 4096 // Default internal render batch elements limits
107#define RL_DEFAULT_BATCH_BUFFERS 1 // Default number of batch buffers (multi-buffering)
108#define RL_DEFAULT_BATCH_DRAWCALLS 256 // Default number of batch draw calls (by state changes: mode, texture)
109#define RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS 4 // Maximum number of textures units that can be activated on batch drawing (SetShaderValueTexture())
110
111#define RL_MAX_MATRIX_STACK_SIZE 32 // Maximum size of internal Matrix stack
112
113#define RL_MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported
114
115#define RL_CULL_DISTANCE_NEAR 0.01 // Default projection matrix near cull distance
116#define RL_CULL_DISTANCE_FAR 1000.0 // Default projection matrix far cull distance
117
118// Default shader vertex attribute locations
119#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0
120#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD 1
121#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL 2
122#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR 3
123#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT 4
124#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5
125#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6
126#if defined(RL_SUPPORT_MESH_GPU_SKINNING)
127 #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEIDS 7
128 #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 8
129#endif
130
131// Default shader vertex attribute names to set location points
132// NOTE: When a new shader is loaded, the following locations are tried to be set for convenience
133#define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION
134#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD
135#define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL
136#define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR
137#define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT
138#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2
139
140#define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix
141#define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix
142#define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION "matProjection" // projection matrix
143#define RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL "matModel" // model matrix
144#define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL "matNormal" // normal matrix (transpose(inverse(matModelView))
145#define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (base tint color, multiplied by texture color)
146#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0)
147#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1)
148#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2)
149
150
151//------------------------------------------------------------------------------------
152// Module: rshapes - Configuration Flags
153//------------------------------------------------------------------------------------
154// Use QUADS instead of TRIANGLES for drawing when possible
155// Some lines-based shapes could still use lines
156#define SUPPORT_QUADS_DRAW_MODE 1
157
158// rshapes: Configuration values
159//------------------------------------------------------------------------------------
160#define SPLINE_SEGMENT_DIVISIONS 24 // Spline segments subdivisions
161
162
163//------------------------------------------------------------------------------------
164// Module: rtextures - Configuration Flags
165//------------------------------------------------------------------------------------
166// Selecte desired fileformats to be supported for image data loading
167#define SUPPORT_FILEFORMAT_PNG 1
168//#define SUPPORT_FILEFORMAT_BMP 1
169//#define SUPPORT_FILEFORMAT_TGA 1
170//#define SUPPORT_FILEFORMAT_JPG 1
171#define SUPPORT_FILEFORMAT_GIF 1
172#define SUPPORT_FILEFORMAT_QOI 1
173//#define SUPPORT_FILEFORMAT_PSD 1
174#define SUPPORT_FILEFORMAT_DDS 1
175//#define SUPPORT_FILEFORMAT_HDR 1
176//#define SUPPORT_FILEFORMAT_PIC 1
177//#define SUPPORT_FILEFORMAT_KTX 1
178//#define SUPPORT_FILEFORMAT_ASTC 1
179//#define SUPPORT_FILEFORMAT_PKM 1
180//#define SUPPORT_FILEFORMAT_PVR 1
181
182// Support image export functionality (.png, .bmp, .tga, .jpg, .qoi)
183#define SUPPORT_IMAGE_EXPORT 1
184// Support procedural image generation functionality (gradient, spot, perlin-noise, cellular)
185#define SUPPORT_IMAGE_GENERATION 1
186// Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop...
187// If not defined, still some functions are supported: ImageFormat(), ImageCrop(), ImageToPOT()
188#define SUPPORT_IMAGE_MANIPULATION 1
189
190
191//------------------------------------------------------------------------------------
192// Module: rtext - Configuration Flags
193//------------------------------------------------------------------------------------
194// Default font is loaded on window initialization to be available for the user to render simple text
195// NOTE: If enabled, uses external module functions to load default raylib font
196#define SUPPORT_DEFAULT_FONT 1
197// Selected desired font fileformats to be supported for loading
198#define SUPPORT_FILEFORMAT_TTF 1
199#define SUPPORT_FILEFORMAT_FNT 1
200//#define SUPPORT_FILEFORMAT_BDF 1
201
202// Support text management functions
203// If not defined, still some functions are supported: TextLength(), TextFormat()
204#define SUPPORT_TEXT_MANIPULATION 1
205
206// On font atlas image generation [GenImageFontAtlas()], add a 3x3 pixels white rectangle
207// at the bottom-right corner of the atlas. It can be useful to for shapes drawing, to allow
208// drawing text and shapes with a single draw call [SetShapesTexture()].
209#define SUPPORT_FONT_ATLAS_WHITE_REC 1
210
211// rtext: Configuration values
212//------------------------------------------------------------------------------------
213#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions:
214 // TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit()
215#define MAX_TEXTSPLIT_COUNT 128 // Maximum number of substrings to split: TextSplit()
216
217
218//------------------------------------------------------------------------------------
219// Module: rmodels - Configuration Flags
220//------------------------------------------------------------------------------------
221// Selected desired model fileformats to be supported for loading
222#define SUPPORT_FILEFORMAT_OBJ 1
223#define SUPPORT_FILEFORMAT_MTL 1
224#define SUPPORT_FILEFORMAT_IQM 1
225#define SUPPORT_FILEFORMAT_GLTF 1
226#define SUPPORT_FILEFORMAT_VOX 1
227#define SUPPORT_FILEFORMAT_M3D 1
228// Support procedural mesh generation functions, uses external par_shapes.h library
229// NOTE: Some generated meshes DO NOT include generated texture coordinates
230#define SUPPORT_MESH_GENERATION 1
231
232// rmodels: Configuration values
233//------------------------------------------------------------------------------------
234#define MAX_MATERIAL_MAPS 12 // Maximum number of shader maps supported
235
236#ifdef RL_SUPPORT_MESH_GPU_SKINNING
237#define MAX_MESH_VERTEX_BUFFERS 9 // Maximum vertex buffers (VBO) per mesh
238#else
239#define MAX_MESH_VERTEX_BUFFERS 7 // Maximum vertex buffers (VBO) per mesh
240#endif
241
242//------------------------------------------------------------------------------------
243// Module: raudio - Configuration Flags
244//------------------------------------------------------------------------------------
245// Desired audio fileformats to be supported for loading
246#define SUPPORT_FILEFORMAT_WAV 1
247#define SUPPORT_FILEFORMAT_OGG 1
248#define SUPPORT_FILEFORMAT_MP3 1
249#define SUPPORT_FILEFORMAT_QOA 1
250//#define SUPPORT_FILEFORMAT_FLAC 1
251#define SUPPORT_FILEFORMAT_XM 1
252#define SUPPORT_FILEFORMAT_MOD 1
253
254// raudio: Configuration values
255//------------------------------------------------------------------------------------
256#define AUDIO_DEVICE_FORMAT ma_format_f32 // Device output format (miniaudio: float-32bit)
257#define AUDIO_DEVICE_CHANNELS 2 // Device output channels: stereo
258#define AUDIO_DEVICE_SAMPLE_RATE 0 // Device sample rate (device default)
259
260#define MAX_AUDIO_BUFFER_POOL_CHANNELS 16 // Maximum number of audio pool channels
261
262//------------------------------------------------------------------------------------
263// Module: utils - Configuration Flags
264//------------------------------------------------------------------------------------
265// Standard file io library (stdio.h) included
266#define SUPPORT_STANDARD_FILEIO 1
267// Show TRACELOG() output messages
268// NOTE: By default LOG_DEBUG traces not shown
269#define SUPPORT_TRACELOG 1
270//#define SUPPORT_TRACELOG_DEBUG 1
271
272// utils: Configuration values
273//------------------------------------------------------------------------------------
274#define MAX_TRACELOG_MSG_LENGTH 256 // Max length of one trace-log message
275
276
277// Enable partial support for clipboard image, only working on SDL3 or
278// being on both Windows OS + GLFW or Windows OS + RGFW
279#define SUPPORT_CLIPBOARD_IMAGE 1
280
281#if defined(SUPPORT_CLIPBOARD_IMAGE)
282 #ifndef STBI_REQUIRED
283 #define STBI_REQUIRED
284 #endif
285
286 #ifndef SUPPORT_FILEFORMAT_BMP // For clipboard image on Windows
287 #define SUPPORT_FILEFORMAT_BMP 1
288 #endif
289
290 #ifndef SUPPORT_FILEFORMAT_PNG // Wayland uses png for prints, at least it was on 22 LTS ubuntu
291 #define SUPPORT_FILEFORMAT_PNG 1
292 #endif
293
294 #ifndef SUPPORT_FILEFORMAT_JPG
295 #define SUPPORT_FILEFORMAT_JPG 1
296 #endif
297
298 #ifndef SUPPORT_MODULE_RTEXTURES
299 #define SUPPORT_MODULE_RTEXTURES 1
300 #endif
301#endif
302
303#endif // CONFIG_H
diff --git a/raylib/src/external/RGFW.h b/raylib/src/external/RGFW.h
new file mode 100644
index 0000000..978536f
--- /dev/null
+++ b/raylib/src/external/RGFW.h
@@ -0,0 +1,9015 @@
1/*
2* Copyright (C) 2023-24 ColleagueRiley
3*
4* libpng license
5*
6* This software is provided 'as-is', without any express or implied
7* warranty. In no event will the authors be held liable for any damages
8* arising from the use of this software.
9*
10* Permission is granted to anyone to use this software for any purpose,
11* including commercial applications, and to alter it and redistribute it
12* freely, subject to the following restrictions:
13*
14* 1. The origin of this software must not be misrepresented; you must not
15* claim that you wrote the original software. If you use this software
16* in a product, an acknowledgment in the product documentation would be
17* appreciated but is not required.
18* 2. Altered source versions must be plainly marked as such, and must not be
19* misrepresented as being the original software.
20* 3. This notice may not be removed or altered from any source distribution.
21*
22*
23*/
24
25/*
26 (MAKE SURE RGFW_IMPLEMENTATION is in exactly one header or you use -D RGFW_IMPLEMENTATION)
27 #define RGFW_IMPLEMENTATION - makes it so source code is included with header
28*/
29
30/*
31 #define RGFW_IMPLEMENTATION - (required) makes it so the source code is included
32 #define RGFW_PRINT_ERRORS - (optional) makes it so RGFW prints errors when they're found
33 #define RGFW_OSMESA - (optional) use OSmesa as backend (instead of system's opengl api + regular opengl)
34 #define RGFW_BUFFER - (optional) just draw directly to (RGFW) window pixel buffer that is drawn to screen (the buffer is in the RGBA format)
35 #define RGFW_EGL - (optional) use EGL for loading an OpenGL context (instead of the system's opengl api)
36 #define RGFW_OPENGL_ES1 - (optional) use EGL to load and use Opengl ES (version 1) for backend rendering (instead of the system's opengl api)
37 This version doesn't work for desktops (I'm pretty sure)
38 #define RGFW_OPENGL_ES2 - (optional) use OpenGL ES (version 2)
39 #define RGFW_OPENGL_ES3 - (optional) use OpenGL ES (version 3)
40 #define RGFW_DIRECTX - (optional) use directX for the rendering backend (rather than opengl) (windows only, defaults to opengl for unix)
41 #define RGFW_WEBGPU - (optional) use webGPU for rendering (Web ONLY)
42 #define RGFW_NO_API - (optional) don't use any rendering API (no opengl, no vulkan, no directX)
43
44 #define RGFW_LINK_EGL (optional) (windows only) if EGL is being used, if EGL functions should be defined dymanically (using GetProcAddress)
45 #define RGFW_LINK_OSMESA (optional) (windows only) if EGL is being used, if OS Mesa functions should be defined dymanically (using GetProcAddress)
46
47 #define RGFW_X11 (optional) (unix only) if X11 should be used. This option is turned on by default by unix systems except for MacOS
48 #define RGFW_WGL_LOAD (optional) (windows only) if WGL should be loaded dynamically during runtime
49 #define RGFW_NO_X11_CURSOR (optional) (unix only) don't use XCursor
50 #define RGFW_NO_X11_CURSOR_PRELOAD (optional) (unix only) Use XCursor, but don't link it in code, (you'll have to link it with -lXcursor)
51
52 #define RGFW_NO_DPI - Do not include calculate DPI (no XRM nor libShcore included)
53
54 #define RGFW_ALLOC_DROPFILES (optional) if room should be allocating for drop files (by default it's global data)
55 #define RGFW_MALLOC x - choose what function to use to allocate, by default the standard malloc is used
56 #define RGFW_CALLOC x - choose what function to use to allocate (calloc), by default the standard calloc is used
57 #define RGFW_FREE x - choose what function to use to allocated memory, by default the standard free is used
58
59 #define RGFW_EXPORT - Use when building RGFW
60 #define RGFW_IMPORT - Use when linking with RGFW (not as a single-header)
61
62 #define RGFW_STD_INT - force the use stdint.h (for systems that might not have stdint.h (msvc))
63*/
64
65/*
66 Credits :
67 EimaMei/Sacode : Much of the code for creating windows using winapi, Wrote the Silicon library, helped with MacOS Support, siliapp.h -> referencing
68
69 stb - This project is heavily inspired by the stb single header files
70
71 GLFW:
72 certain parts of winapi and X11 are very poorly documented,
73 GLFW's source code was referenced and used throughout the project (used code is marked in some way),
74 this mainly includes, code for drag and drops, code for setting the icon to a bitmap and the code for managing the clipboard for X11 (as these parts are not documented very well)
75
76 GLFW Copyright, https::/github.com/GLFW/GLFW
77
78 Copyright (c) 2002-2006 Marcus Geelnard
79 Copyright (c) 2006-2019 Camilla Löwy
80
81 contributors : (feel free to put yourself here if you contribute)
82 krisvers -> code review
83 EimaMei (SaCode) -> code review
84 Code-Nycticebus -> bug fixes
85 Rob Rohan -> X11 bugs and missing features, MacOS/Cocoa fixing memory issues/bugs
86 AICDG (@THISISAGOODNAME) -> vulkan support (example)
87 @Easymode -> support, testing/debugging, bug fixes and reviews
88 Joshua Rowe (omnisci3nce) - bug fix, review (macOS)
89 @lesleyrs -> bug fix, review (OpenGL)
90 Nick Porcino (meshula) - testing, organization, review (MacOS, examples)
91*/
92
93#if _MSC_VER
94 #pragma comment(lib, "gdi32")
95 #pragma comment(lib, "shell32")
96 #pragma comment(lib, "opengl32")
97 #pragma comment(lib, "winmm")
98 #pragma comment(lib, "user32")
99#endif
100
101#ifndef RGFW_MALLOC
102 #include <stdlib.h>
103
104 #ifndef __USE_POSIX199309
105 #define __USE_POSIX199309
106 #endif
107
108 #include <time.h>
109 #define RGFW_MALLOC malloc
110 #define RGFW_CALLOC calloc
111 #define RGFW_FREE free
112#endif
113
114#if !_MSC_VER
115 #ifndef inline
116 #ifndef __APPLE__
117 #define inline __inline
118 #endif
119 #endif
120#endif
121
122#ifdef RGFW_WIN95 /* for windows 95 testing (not that it really works) */
123 #define RGFW_NO_MONITOR
124 #define RGFW_NO_PASSTHROUGH
125#endif
126
127#if defined(RGFW_EXPORT) || defined(RGFW_IMPORT)
128 #if defined(_WIN32)
129 #if defined(__TINYC__) && (defined(RGFW_EXPORT) || defined(RGFW_IMPORT))
130 #define __declspec(x) __attribute__((x))
131 #endif
132
133 #if defined(RGFW_EXPORT)
134 #define RGFWDEF __declspec(dllexport)
135 #else
136 #define RGFWDEF __declspec(dllimport)
137 #endif
138 #else
139 #if defined(RGFW_EXPORT)
140 #define RGFWDEF __attribute__((visibility("default")))
141 #endif
142 #endif
143#endif
144
145#ifndef RGFWDEF
146 #ifdef __clang__
147 #define RGFWDEF static inline
148 #else
149 #define RGFWDEF inline
150 #endif
151#endif
152
153#ifndef RGFW_ENUM
154 #define RGFW_ENUM(type, name) type name; enum
155#endif
156
157#ifndef RGFW_UNUSED
158 #define RGFW_UNUSED(x) (void)(x);
159#endif
160
161#if defined(__cplusplus) && !defined(__EMSCRIPTEN__)
162 extern "C" {
163#endif
164
165 /* makes sure the header file part is only defined once by default */
166#ifndef RGFW_HEADER
167
168#define RGFW_HEADER
169
170#if !defined(u8)
171 #if ((defined(_MSC_VER) || defined(__SYMBIAN32__)) && !defined(RGFW_STD_INT)) /* MSVC might not have stdint.h */
172 typedef unsigned char u8;
173 typedef signed char i8;
174 typedef unsigned short u16;
175 typedef signed short i16;
176 typedef unsigned int u32;
177 typedef signed int i32;
178 typedef unsigned long u64;
179 typedef signed long i64;
180 #else /* use stdint standard types instead of c ""standard"" types */
181 #include <stdint.h>
182
183 typedef uint8_t u8;
184 typedef int8_t i8;
185 typedef uint16_t u16;
186 typedef int16_t i16;
187 typedef uint32_t u32;
188 typedef int32_t i32;
189 typedef uint64_t u64;
190 typedef int64_t i64;
191 #endif
192#endif
193
194#if !defined(b8) /* RGFW bool type */
195 typedef u8 b8;
196 typedef u32 b32;
197#endif
198
199#define RGFW_TRUE (!(0))
200#define RGFW_FALSE 0
201
202/* thse OS macros looks better & are standardized */
203/* plus it helps with cross-compiling */
204
205#ifdef __EMSCRIPTEN__
206 #define RGFW_WEBASM
207
208 #if !defined(RGFW_NO_API) && !defined(RGFW_WEBGPU)
209 #define RGFW_OPENGL
210 #endif
211
212 #ifdef RGFW_EGL
213 #undef RGFW_EGL
214 #endif
215
216 #include <emscripten/html5.h>
217 #include <emscripten/key_codes.h>
218
219 #ifdef RGFW_WEBGPU
220 #include <emscripten/html5_webgpu.h>
221 #endif
222#endif
223
224#if defined(RGFW_X11) && defined(__APPLE__)
225 #define RGFW_MACOS_X11
226 #undef __APPLE__
227#endif
228
229#if defined(_WIN32) && !defined(RGFW_X11) && !defined(RGFW_WEBASM) /* (if you're using X11 on windows some how) */
230 #define RGFW_WINDOWS
231
232 /* make sure the correct architecture is defined */
233 #if defined(_WIN64)
234 #define _AMD64_
235 #undef _X86_
236 #else
237 #undef _AMD64_
238 #ifndef _X86_
239 #define _X86_
240 #endif
241 #endif
242
243 #ifndef RGFW_NO_XINPUT
244 #ifdef __MINGW32__ /* try to find the right header */
245 #include <xinput.h>
246 #else
247 #include <XInput.h>
248 #endif
249 #endif
250
251 #if defined(RGFW_DIRECTX)
252 #include <d3d11.h>
253 #include <dxgi.h>
254 #include <dxgi.h>
255 #include <d3dcompiler.h>
256
257 #ifndef __cplusplus
258 #define __uuidof(T) IID_##T
259 #endif
260 #endif
261
262#elif defined(RGFW_WAYLAND)
263 #if !defined(RGFW_NO_API) && (!defined(RGFW_BUFFER) || defined(RGFW_OPENGL))
264 #define RGFW_EGL
265 #define RGFW_OPENGL
266 #include <wayland-egl.h>
267 #endif
268
269 #include <wayland-client.h>
270#elif (defined(__unix__) || defined(RGFW_MACOS_X11) || defined(RGFW_X11)) && !defined(RGFW_WEBASM)
271 #define RGFW_MACOS_X11
272 #define RGFW_X11
273 #include <X11/Xlib.h>
274#elif defined(__APPLE__) && !defined(RGFW_MACOS_X11) && !defined(RGFW_X11) && !defined(RGFW_WEBASM)
275 #define RGFW_MACOS
276#endif
277
278#if (defined(RGFW_OPENGL_ES1) || defined(RGFW_OPENGL_ES2) || defined(RGFW_OPENGL_ES3)) && !defined(RGFW_EGL)
279 #define RGFW_EGL
280#endif
281
282#if !defined(RGFW_OSMESA) && !defined(RGFW_EGL) && !defined(RGFW_OPENGL) && !defined(RGFW_DIRECTX) && !defined(RGFW_BUFFER) && !defined(RGFW_NO_API)
283 #define RGFW_OPENGL
284#endif
285
286#ifdef RGFW_EGL
287 #include <EGL/egl.h>
288#elif defined(RGFW_OSMESA)
289 #ifndef __APPLE__
290 #include <GL/osmesa.h>
291 #else
292 #include <OpenGL/osmesa.h>
293 #endif
294#endif
295
296#if defined(RGFW_OPENGL) && defined(RGFW_X11)
297 #ifndef GLX_MESA_swap_control
298 #define GLX_MESA_swap_control
299 #endif
300 #include <GL/glx.h> /* GLX defs, xlib.h, gl.h */
301#endif
302
303#ifndef RGFW_ALPHA
304 #define RGFW_ALPHA 128 /* alpha value for RGFW_TRANSPARENT_WINDOW (WINAPI ONLY, macOS + linux don't need this) */
305#endif
306
307/*! Optional arguments for making a windows */
308#define RGFW_TRANSPARENT_WINDOW (1L<<9) /*!< the window is transparent (only properly works on X11 and MacOS, although it's although for windows) */
309#define RGFW_NO_BORDER (1L<<3) /*!< the window doesn't have border */
310#define RGFW_NO_RESIZE (1L<<4) /*!< the window cannot be resized by the user */
311#define RGFW_ALLOW_DND (1L<<5) /*!< the window supports drag and drop*/
312#define RGFW_HIDE_MOUSE (1L<<6) /*! the window should hide the mouse or not (can be toggled later on) using `RGFW_window_mouseShow*/
313#define RGFW_FULLSCREEN (1L<<8) /* the window is fullscreen by default or not */
314#define RGFW_CENTER (1L<<10) /*! center the window on the screen */
315#define RGFW_OPENGL_SOFTWARE (1L<<11) /*! use OpenGL software rendering */
316#define RGFW_COCOA_MOVE_TO_RESOURCE_DIR (1L << 12) /* (cocoa only), move to resource folder */
317#define RGFW_SCALE_TO_MONITOR (1L << 13) /* scale the window to the screen */
318#define RGFW_NO_INIT_API (1L << 2) /* DO not init an API (mostly for bindings, you should use `#define RGFW_NO_API` in C */
319
320#define RGFW_NO_GPU_RENDER (1L<<14) /* don't render (using the GPU based API)*/
321#define RGFW_NO_CPU_RENDER (1L<<15) /* don't render (using the CPU based buffer rendering)*/
322#define RGFW_WINDOW_HIDE (1L << 16)/* the window is hidden */
323
324typedef RGFW_ENUM(u8, RGFW_event_types) {
325 /*! event codes */
326 RGFW_keyPressed = 1, /* a key has been pressed */
327 RGFW_keyReleased, /*!< a key has been released*/
328 /*! key event note
329 the code of the key pressed is stored in
330 RGFW_Event.keyCode
331 !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!!
332
333 while a string version is stored in
334 RGFW_Event.KeyString
335
336 RGFW_Event.lockState holds the current lockState
337 this means if CapsLock, NumLock are active or not
338 */
339 RGFW_mouseButtonPressed, /*!< a mouse button has been pressed (left,middle,right)*/
340 RGFW_mouseButtonReleased, /*!< a mouse button has been released (left,middle,right)*/
341 RGFW_mousePosChanged, /*!< the position of the mouse has been changed*/
342 /*! mouse event note
343 the x and y of the mouse can be found in the vector, RGFW_Event.point
344
345 RGFW_Event.button holds which mouse button was pressed
346 */
347 RGFW_jsButtonPressed, /*!< a joystick button was pressed */
348 RGFW_jsButtonReleased, /*!< a joystick button was released */
349 RGFW_jsAxisMove, /*!< an axis of a joystick was moved*/
350 /*! joystick event note
351 RGFW_Event.joystick holds which joystick was altered, if any
352 RGFW_Event.button holds which joystick button was pressed
353
354 RGFW_Event.axis holds the data of all the axis
355 RGFW_Event.axisCount says how many axis there are
356 */
357 RGFW_windowMoved, /*!< the window was moved (by the user) */
358 RGFW_windowResized, /*!< the window was resized (by the user), [on webASM this means the browser was resized] */
359 RGFW_focusIn, /*!< window is in focus now */
360 RGFW_focusOut, /*!< window is out of focus now */
361 RGFW_mouseEnter, /* mouse entered the window */
362 RGFW_mouseLeave, /* mouse left the window */
363 RGFW_windowRefresh, /* The window content needs to be refreshed */
364
365 /* attribs change event note
366 The event data is sent straight to the window structure
367 with win->r.x, win->r.y, win->r.w and win->r.h
368 */
369 RGFW_quit, /*!< the user clicked the quit button*/
370 RGFW_dnd, /*!< a file has been dropped into the window*/
371 RGFW_dnd_init /*!< the start of a dnd event, when the place where the file drop is known */
372 /* dnd data note
373 The x and y coords of the drop are stored in the vector RGFW_Event.point
374
375 RGFW_Event.droppedFilesCount holds how many files were dropped
376
377 This is also the size of the array which stores all the dropped file string,
378 RGFW_Event.droppedFiles
379 */
380};
381
382/*! mouse button codes (RGFW_Event.button) */
383#define RGFW_mouseLeft 1 /*!< left mouse button is pressed*/
384#define RGFW_mouseMiddle 2 /*!< mouse-wheel-button is pressed*/
385#define RGFW_mouseRight 3 /*!< right mouse button is pressed*/
386#define RGFW_mouseScrollUp 4 /*!< mouse wheel is scrolling up*/
387#define RGFW_mouseScrollDown 5 /*!< mouse wheel is scrolling down*/
388
389#ifndef RGFW_MAX_PATH
390#define RGFW_MAX_PATH 260 /* max length of a path (for dnd) */
391#endif
392#ifndef RGFW_MAX_DROPS
393#define RGFW_MAX_DROPS 260 /* max items you can drop at once */
394#endif
395
396
397/* for RGFW_Event.lockstate */
398#define RGFW_CAPSLOCK (1L << 1)
399#define RGFW_NUMLOCK (1L << 2)
400
401/*! joystick button codes (based on xbox/playstation), you may need to change these values per controller */
402#ifndef RGFW_joystick_codes
403 typedef RGFW_ENUM(u8, RGFW_joystick_codes) {
404 RGFW_JS_A = 0, /*!< or PS X button */
405 RGFW_JS_B = 1, /*!< or PS circle button */
406 RGFW_JS_Y = 2, /*!< or PS triangle button */
407 RGFW_JS_X = 3, /*!< or PS square button */
408 RGFW_JS_START = 9, /*!< start button */
409 RGFW_JS_SELECT = 8, /*!< select button */
410 RGFW_JS_HOME = 10, /*!< home button */
411 RGFW_JS_UP = 13, /*!< dpad up */
412 RGFW_JS_DOWN = 14, /*!< dpad down*/
413 RGFW_JS_LEFT = 15, /*!< dpad left */
414 RGFW_JS_RIGHT = 16, /*!< dpad right */
415 RGFW_JS_L1 = 4, /*!< left bump */
416 RGFW_JS_L2 = 5, /*!< left trigger*/
417 RGFW_JS_R1 = 6, /*!< right bumper */
418 RGFW_JS_R2 = 7, /*!< right trigger */
419 };
420#endif
421
422/*! basic vector type, if there's not already a point/vector type of choice */
423#ifndef RGFW_point
424 typedef struct { i32 x, y; } RGFW_point;
425#endif
426
427/*! basic rect type, if there's not already a rect type of choice */
428#ifndef RGFW_rect
429 typedef struct { i32 x, y, w, h; } RGFW_rect;
430#endif
431
432/*! basic area type, if there's not already a area type of choice */
433#ifndef RGFW_area
434 typedef struct { u32 w, h; } RGFW_area;
435#endif
436
437#ifndef __cplusplus
438#define RGFW_POINT(x, y) (RGFW_point){(i32)(x), (i32)(y)}
439#define RGFW_RECT(x, y, w, h) (RGFW_rect){(i32)(x), (i32)(y), (i32)(w), (i32)(h)}
440#define RGFW_AREA(w, h) (RGFW_area){(u32)(w), (u32)(h)}
441#else
442#define RGFW_POINT(x, y) {(i32)(x), (i32)(y)}
443#define RGFW_RECT(x, y, w, h) {(i32)(x), (i32)(y), (i32)(w), (i32)(h)}
444#define RGFW_AREA(w, h) {(u32)(w), (u32)(h)}
445#endif
446
447#ifndef RGFW_NO_MONITOR
448 /*! structure for monitor data */
449 typedef struct RGFW_monitor {
450 char name[128]; /*!< monitor name */
451 RGFW_rect rect; /*!< monitor Workarea */
452 float scaleX, scaleY; /*!< monitor content scale*/
453 float physW, physH; /*!< monitor physical size */
454 } RGFW_monitor;
455
456 /*
457 NOTE : Monitor functions should be ran only as many times as needed (not in a loop)
458 */
459
460 /*! get an array of all the monitors (max 6) */
461 RGFWDEF RGFW_monitor* RGFW_getMonitors(void);
462 /*! get the primary monitor */
463 RGFWDEF RGFW_monitor RGFW_getPrimaryMonitor(void);
464#endif
465
466/* NOTE: some parts of the data can represent different things based on the event (read comments in RGFW_Event struct) */
467/*! Event structure for checking/getting events */
468typedef struct RGFW_Event {
469 char keyName[16]; /*!< key name of event*/
470
471 /*! drag and drop data */
472 /* 260 max paths with a max length of 260 */
473#ifdef RGFW_ALLOC_DROPFILES
474 char** droppedFiles;
475#else
476 char droppedFiles[RGFW_MAX_DROPS][RGFW_MAX_PATH]; /*!< dropped files*/
477#endif
478 u32 droppedFilesCount; /*!< house many files were dropped */
479
480 u32 type; /*!< which event has been sent?*/
481 RGFW_point point; /*!< mouse x, y of event (or drop point) */
482
483 u8 keyCode; /*!< keycode of event !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!! */
484
485 b8 repeat; /*!< key press event repeated (the key is being held) */
486 b8 inFocus; /*!< if the window is in focus or not (this is always true for MacOS windows due to the api being weird) */
487
488 u8 lockState;
489
490 u8 button; /* !< which mouse button was pressed */
491 double scroll; /*!< the raw mouse scroll value */
492
493 u16 joystick; /*! which joystick this event applies to (if applicable to any) */
494 u8 axisesCount; /*!< number of axises */
495 RGFW_point axis[2]; /*!< x, y of axises (-100 to 100) */
496
497 u64 frameTime, frameTime2; /*!< this is used for counting the fps */
498} RGFW_Event;
499
500/*! source data for the window (used by the APIs) */
501typedef struct RGFW_window_src {
502#ifdef RGFW_WINDOWS
503 HWND window; /*!< source window */
504 HDC hdc; /*!< source HDC */
505 u32 hOffset; /*!< height offset for window */
506 #if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL)
507 HGLRC ctx; /*!< source graphics context */
508 #elif defined(RGFW_OSMESA)
509 OSMesaContext ctx;
510 #elif defined(RGFW_DIRECTX)
511 IDXGISwapChain* swapchain;
512 ID3D11RenderTargetView* renderTargetView;
513 ID3D11DepthStencilView* pDepthStencilView;
514 #elif defined(RGFW_EGL)
515 EGLSurface EGL_surface;
516 EGLDisplay EGL_display;
517 EGLContext EGL_context;
518 #endif
519
520 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
521 HDC hdcMem;
522 HBITMAP bitmap;
523 #endif
524 RGFW_area maxSize, minSize; /*!< for setting max/min resize (RGFW_WINDOWS) */
525#elif defined(RGFW_X11)
526 Display* display; /*!< source display */
527 Window window; /*!< source window */
528 #if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL)
529 GLXContext ctx; /*!< source graphics context */
530 #elif defined(RGFW_OSMESA)
531 OSMesaContext ctx;
532 #elif defined(RGFW_EGL)
533 EGLSurface EGL_surface;
534 EGLDisplay EGL_display;
535 EGLContext EGL_context;
536 #endif
537
538#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
539 XImage* bitmap;
540 GC gc;
541#endif
542#elif defined(RGFW_WAYLAND)
543 struct wl_display* display;
544 struct wl_surface* surface;
545 struct wl_buffer* wl_buffer;
546 struct wl_keyboard* keyboard;
547
548 struct xdg_surface* xdg_surface;
549 struct xdg_toplevel* xdg_toplevel;
550 struct zxdg_toplevel_decoration_v1* decoration;
551 RGFW_Event events[20];
552 i32 eventLen;
553 size_t eventIndex;
554 #if defined(RGFW_EGL)
555 struct wl_egl_window* window;
556 EGLSurface EGL_surface;
557 EGLDisplay EGL_display;
558 EGLContext EGL_context;
559 #elif defined(RGFW_OSMESA)
560 OSMesaContext ctx;
561 #endif
562#elif defined(RGFW_MACOS)
563 u32 display;
564 void* displayLink;
565 void* window;
566 b8 dndPassed;
567#if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL)
568 void* ctx; /*!< source graphics context */
569#elif defined(RGFW_OSMESA)
570 OSMesaContext ctx;
571#elif defined(RGFW_EGL)
572 EGLSurface EGL_surface;
573 EGLDisplay EGL_display;
574 EGLContext EGL_context;
575#endif
576
577 void* view; /*apple viewpoint thingy*/
578
579#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
580 void* bitmap; /*!< API's bitmap for storing or managing */
581 void* image;
582#endif
583#elif defined(RGFW_WEBASM)
584 #ifdef RGFW_WEBGPU
585 WGPUInstance ctx;
586 WGPUDevice device;
587 WGPUQueue queue;
588 #else
589 EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx;
590 #endif
591#endif
592} RGFW_window_src;
593
594
595
596typedef struct RGFW_window {
597 RGFW_window_src src; /*!< src window data */
598
599#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
600 u8* buffer; /*!< buffer for non-GPU systems (OSMesa, basic software rendering) */
601 /* when rendering using RGFW_BUFFER, the buffer is in the RGBA format */
602#endif
603 void* userPtr; /* ptr for usr data */
604
605 RGFW_Event event; /*!< current event */
606
607 RGFW_rect r; /*!< the x, y, w and h of the struct */
608
609 RGFW_point _lastMousePoint; /*!< last cusor point (for raw mouse data) */
610
611 u32 _winArgs; /*!< windows args (for RGFW to check) */
612} RGFW_window; /*!< Window structure for managing the window */
613
614#if defined(RGFW_X11) || defined(RGFW_MACOS)
615 typedef u64 RGFW_thread; /*!< thread type unix */
616#else
617 typedef void* RGFW_thread; /*!< thread type for window */
618#endif
619
620/** * @defgroup Window_management
621* @{ */
622
623
624/*!
625 * the class name for X11 and WinAPI. apps with the same class will be grouped by the WM
626 * by default the class name will == the root window's name
627*/
628RGFWDEF void RGFW_setClassName(char* name);
629
630/*! this has to be set before createWindow is called, else the fulscreen size is used */
631RGFWDEF void RGFW_setBufferSize(RGFW_area size); /*!< the buffer cannot be resized (by RGFW) */
632
633RGFWDEF RGFW_window* RGFW_createWindow(
634 const char* name, /* name of the window */
635 RGFW_rect rect, /* rect of window */
636 u16 args /* extra arguments (NULL / (u16)0 means no args used)*/
637); /*!< function to create a window struct */
638
639/*! get the size of the screen to an area struct */
640RGFWDEF RGFW_area RGFW_getScreenSize(void);
641
642/*!
643 this function checks an *individual* event (and updates window structure attributes)
644 this means, using this function without a while loop may cause event lag
645
646 ex.
647
648 while (RGFW_window_checkEvent(win) != NULL) [this keeps checking events until it reaches the last one]
649
650 this function is optional if you choose to use event callbacks,
651 although you still need some way to tell RGFW to process events eg. `RGFW_window_checkEvents`
652*/
653
654RGFWDEF RGFW_Event* RGFW_window_checkEvent(RGFW_window* win); /*!< check current event (returns a pointer to win->event or NULL if there is no event)*/
655
656/*!
657 for RGFW_window_eventWait and RGFW_window_checkEvents
658 waitMS -> Allows th e function to keep checking for events even after `RGFW_window_checkEvent == NULL`
659 if waitMS == 0, the loop will not wait for events
660 if waitMS == a positive integer, the loop will wait that many miliseconds after there are no more events until it returns
661 if waitMS == a negative integer, the loop will not return until it gets another event
662*/
663typedef RGFW_ENUM(i32, RGFW_eventWait) {
664 RGFW_NEXT = -1,
665 RGFW_NO_WAIT = 0
666};
667
668/*! sleep until RGFW gets an event or the timer ends (defined by OS) */
669RGFWDEF void RGFW_window_eventWait(RGFW_window* win, i32 waitMS);
670
671/*!
672 check all the events until there are none left,
673 this should only be used if you're using callbacks only
674*/
675RGFWDEF void RGFW_window_checkEvents(RGFW_window* win, i32 waitMS);
676
677/*!
678 Tell RGFW_window_eventWait to stop waiting, to be ran from another thread
679*/
680RGFWDEF void RGFW_stopCheckEvents(void);
681
682/*! window managment functions*/
683RGFWDEF void RGFW_window_close(RGFW_window* win); /*!< close the window and free leftover data */
684
685/*! moves window to a given point */
686RGFWDEF void RGFW_window_move(RGFW_window* win,
687 RGFW_point v/*!< new pos*/
688);
689
690#ifndef RGFW_NO_MONITOR
691 /*! move to a specific monitor */
692 RGFWDEF void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m /* monitor */);
693#endif
694
695/*! resize window to a current size/area */
696RGFWDEF void RGFW_window_resize(RGFW_window* win, /*!< source window */
697 RGFW_area a/*!< new size*/
698);
699
700/*! set the minimum size a user can shrink a window to a given size/area */
701RGFWDEF void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a);
702/*! set the minimum size a user can extend a window to a given size/area */
703RGFWDEF void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a);
704
705RGFWDEF void RGFW_window_maximize(RGFW_window* win); /*!< maximize the window size */
706RGFWDEF void RGFW_window_minimize(RGFW_window* win); /*!< minimize the window (in taskbar (per OS))*/
707RGFWDEF void RGFW_window_restore(RGFW_window* win); /*!< restore the window from minimized (per OS)*/
708
709/*! if the window should have a border or not (borderless) based on bool value of `border` */
710RGFWDEF void RGFW_window_setBorder(RGFW_window* win, b8 border);
711
712/*! turn on / off dnd (RGFW_ALLOW_DND stil must be passed to the window)*/
713RGFWDEF void RGFW_window_setDND(RGFW_window* win, b8 allow);
714
715#ifndef RGFW_NO_PASSTHROUGH
716 /*!! turn on / off mouse passthrough */
717 RGFWDEF void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough);
718#endif
719
720/*! rename window to a given string */
721RGFWDEF void RGFW_window_setName(RGFW_window* win,
722 char* name
723);
724
725RGFWDEF void RGFW_window_setIcon(RGFW_window* win, /*!< source window */
726 u8* icon /*!< icon bitmap */,
727 RGFW_area a /*!< width and height of the bitmap*/,
728 i32 channels /*!< how many channels the bitmap has (rgb : 3, rgba : 4) */
729); /*!< image resized by default */
730
731/*!< sets mouse to bitmap (very simular to RGFW_window_setIcon), image NOT resized by default*/
732RGFWDEF void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels);
733
734/*!< sets the mouse to a standard API cursor (based on RGFW_MOUSE, as seen at the end of the RGFW_HEADER part of this file) */
735RGFWDEF void RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse);
736
737RGFWDEF void RGFW_window_setMouseDefault(RGFW_window* win); /*!< sets the mouse to the default mouse icon */
738/*
739 Locks cursor at the center of the window
740 win->event.point become raw mouse movement data
741
742 this is useful for a 3D camera
743*/
744RGFWDEF void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area);
745/*! stop holding the mouse and let it move freely */
746RGFWDEF void RGFW_window_mouseUnhold(RGFW_window* win);
747
748/*! hide the window */
749RGFWDEF void RGFW_window_hide(RGFW_window* win);
750/*! show the window */
751RGFWDEF void RGFW_window_show(RGFW_window* win);
752
753/*
754 makes it so `RGFW_window_shouldClose` returns true
755 by setting the window event.type to RGFW_quit
756*/
757RGFWDEF void RGFW_window_setShouldClose(RGFW_window* win);
758
759/*! where the mouse is on the screen */
760RGFWDEF RGFW_point RGFW_getGlobalMousePoint(void);
761
762/*! where the mouse is on the window */
763RGFWDEF RGFW_point RGFW_window_getMousePoint(RGFW_window* win);
764
765/*! show the mouse or hide the mouse*/
766RGFWDEF void RGFW_window_showMouse(RGFW_window* win, i8 show);
767/*! move the mouse to a set x, y pos*/
768RGFWDEF void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v);
769
770/*! if the window should close (RGFW_close was sent or escape was pressed) */
771RGFWDEF b8 RGFW_window_shouldClose(RGFW_window* win);
772/*! if window is fullscreen'd */
773RGFWDEF b8 RGFW_window_isFullscreen(RGFW_window* win);
774/*! if window is hidden */
775RGFWDEF b8 RGFW_window_isHidden(RGFW_window* win);
776/*! if window is minimized */
777RGFWDEF b8 RGFW_window_isMinimized(RGFW_window* win);
778/*! if window is maximized */
779RGFWDEF b8 RGFW_window_isMaximized(RGFW_window* win);
780
781/** @} */
782
783/** * @defgroup Monitor
784* @{ */
785
786#ifndef RGFW_NO_MONITOR
787/*
788scale the window to the monitor,
789this is run by default if the user uses the arg `RGFW_SCALE_TO_MONITOR` during window creation
790*/
791RGFWDEF void RGFW_window_scaleToMonitor(RGFW_window* win);
792/*! get the struct of the window's monitor */
793RGFWDEF RGFW_monitor RGFW_window_getMonitor(RGFW_window* win);
794#endif
795
796/** @} */
797
798/** * @defgroup Input
799* @{ */
800
801/*error handling*/
802RGFWDEF b8 RGFW_Error(void); /*!< returns true if an error has occurred (doesn't print errors itself) */
803
804/*! returns true if the key should be shifted */
805RGFWDEF b8 RGFW_shouldShift(u32 keycode, u8 lockState);
806
807/*! get char from RGFW keycode (using a LUT), uses shift'd version if shift = true */
808RGFWDEF char RGFW_keyCodeToChar(u32 keycode, b8 shift);
809/*! get char from RGFW keycode (using a LUT), uses lockState for shouldShift) */
810RGFWDEF char RGFW_keyCodeToCharAuto(u32 keycode, u8 lockState);
811
812/*! if window == NULL, it checks if the key is pressed globally. Otherwise, it checks only if the key is pressed while the window in focus.*/
813RGFWDEF b8 RGFW_isPressed(RGFW_window* win, u8 key); /*!< if key is pressed (key code)*/
814
815RGFWDEF b8 RGFW_wasPressed(RGFW_window* win, u8 key); /*!< if key was pressed (checks previous state only) (key code)*/
816
817RGFWDEF b8 RGFW_isHeld(RGFW_window* win, u8 key); /*!< if key is held (key code)*/
818RGFWDEF b8 RGFW_isReleased(RGFW_window* win, u8 key); /*!< if key is released (key code)*/
819
820/* if a key is pressed and then released, pretty much the same as RGFW_isReleased */
821RGFWDEF b8 RGFW_isClicked(RGFW_window* win, u8 key /*!< key code*/);
822
823/*! if a mouse button is pressed */
824RGFWDEF b8 RGFW_isMousePressed(RGFW_window* win, u8 button /*!< mouse button code */ );
825/*! if a mouse button is held */
826RGFWDEF b8 RGFW_isMouseHeld(RGFW_window* win, u8 button /*!< mouse button code */ );
827/*! if a mouse button was released */
828RGFWDEF b8 RGFW_isMouseReleased(RGFW_window* win, u8 button /*!< mouse button code */ );
829/*! if a mouse button was pressed (checks previous state only) */
830RGFWDEF b8 RGFW_wasMousePressed(RGFW_window* win, u8 button /*!< mouse button code */ );
831/** @} */
832
833/** * @defgroup Clipboard
834* @{ */
835RGFWDEF char* RGFW_readClipboard(size_t* size); /*!< read clipboard data */
836RGFWDEF void RGFW_clipboardFree(char* str); /*!< the string returned from RGFW_readClipboard must be freed */
837
838RGFWDEF void RGFW_writeClipboard(const char* text, u32 textLen); /*!< write text to the clipboard */
839/** @} */
840
841/**
842
843
844 Event callbacks,
845 these are completely optional, you can use the normal
846 RGFW_checkEvent() method if you prefer that
847
848* @defgroup Callbacks
849* @{
850*/
851
852/*! RGFW_windowMoved, the window and its new rect value */
853typedef void (* RGFW_windowmovefunc)(RGFW_window* win, RGFW_rect r);
854/*! RGFW_windowResized, the window and its new rect value */
855typedef void (* RGFW_windowresizefunc)(RGFW_window* win, RGFW_rect r);
856/*! RGFW_quit, the window that was closed */
857typedef void (* RGFW_windowquitfunc)(RGFW_window* win);
858/*! RGFW_focusIn / RGFW_focusOut, the window who's focus has changed and if its inFocus */
859typedef void (* RGFW_focusfunc)(RGFW_window* win, b8 inFocus);
860/*! RGFW_mouseEnter / RGFW_mouseLeave, the window that changed, the point of the mouse (enter only) and if the mouse has entered */
861typedef void (* RGFW_mouseNotifyfunc)(RGFW_window* win, RGFW_point point, b8 status);
862/*! RGFW_mousePosChanged, the window that the move happened on and the new point of the mouse */
863typedef void (* RGFW_mouseposfunc)(RGFW_window* win, RGFW_point point);
864/*! RGFW_dnd_init, the window, the point of the drop on the windows */
865typedef void (* RGFW_dndInitfunc)(RGFW_window* win, RGFW_point point);
866/*! RGFW_windowRefresh, the window that needs to be refreshed */
867typedef void (* RGFW_windowrefreshfunc)(RGFW_window* win);
868/*! RGFW_keyPressed / RGFW_keyReleased, the window that got the event, the keycode, the string version, the state of mod keys, if it was a press (else it's a release) */
869typedef void (* RGFW_keyfunc)(RGFW_window* win, u32 keycode, char keyName[16], u8 lockState, b8 pressed);
870/*! RGFW_mouseButtonPressed / RGFW_mouseButtonReleased, the window that got the event, the button that was pressed, the scroll value, if it was a press (else it's a release) */
871typedef void (* RGFW_mousebuttonfunc)(RGFW_window* win, u8 button, double scroll, b8 pressed);
872/*! RGFW_jsButtonPressed / RGFW_jsButtonReleased, the window that got the event, the button that was pressed, the scroll value, if it was a press (else it's a release) */
873typedef void (* RGFW_jsButtonfunc)(RGFW_window* win, u16 joystick, u8 button, b8 pressed);
874/*! RGFW_jsAxisMove, the window that got the event, the joystick in question, the axis values and the amount of axises */
875typedef void (* RGFW_jsAxisfunc)(RGFW_window* win, u16 joystick, RGFW_point axis[2], u8 axisesCount);
876
877
878/*! RGFW_dnd, the window that had the drop, the drop data and the amount files dropped returns previous callback function (if it was set) */
879#ifdef RGFW_ALLOC_DROPFILES
880 typedef void (* RGFW_dndfunc)(RGFW_window* win, char** droppedFiles, u32 droppedFilesCount);
881#else
882 typedef void (* RGFW_dndfunc)(RGFW_window* win, char droppedFiles[RGFW_MAX_DROPS][RGFW_MAX_PATH], u32 droppedFilesCount);
883#endif
884/*! set callback for a window move event returns previous callback function (if it was set) */
885RGFWDEF RGFW_windowmovefunc RGFW_setWindowMoveCallback(RGFW_windowmovefunc func);
886/*! set callback for a window resize event returns previous callback function (if it was set) */
887RGFWDEF RGFW_windowresizefunc RGFW_setWindowResizeCallback(RGFW_windowresizefunc func);
888/*! set callback for a window quit event returns previous callback function (if it was set) */
889RGFWDEF RGFW_windowquitfunc RGFW_setWindowQuitCallback(RGFW_windowquitfunc func);
890/*! set callback for a mouse move event returns previous callback function (if it was set) */
891RGFWDEF RGFW_mouseposfunc RGFW_setMousePosCallback(RGFW_mouseposfunc func);
892/*! set callback for a window refresh event returns previous callback function (if it was set) */
893RGFWDEF RGFW_windowrefreshfunc RGFW_setWindowRefreshCallback(RGFW_windowrefreshfunc func);
894/*! set callback for a window focus change event returns previous callback function (if it was set) */
895RGFWDEF RGFW_focusfunc RGFW_setFocusCallback(RGFW_focusfunc func);
896/*! set callback for a mouse notify event returns previous callback function (if it was set) */
897RGFWDEF RGFW_mouseNotifyfunc RGFW_setMouseNotifyCallBack(RGFW_mouseNotifyfunc func);
898/*! set callback for a drop event event returns previous callback function (if it was set) */
899RGFWDEF RGFW_dndfunc RGFW_setDndCallback(RGFW_dndfunc func);
900/*! set callback for a start of a drop event returns previous callback function (if it was set) */
901RGFWDEF RGFW_dndInitfunc RGFW_setDndInitCallback(RGFW_dndInitfunc func);
902/*! set callback for a key (press / release ) event returns previous callback function (if it was set) */
903RGFWDEF RGFW_keyfunc RGFW_setKeyCallback(RGFW_keyfunc func);
904/*! set callback for a mouse button (press / release ) event returns previous callback function (if it was set) */
905RGFWDEF RGFW_mousebuttonfunc RGFW_setMouseButtonCallback(RGFW_mousebuttonfunc func);
906/*! set callback for a controller button (press / release ) event returns previous callback function (if it was set) */
907RGFWDEF RGFW_jsButtonfunc RGFW_setjsButtonCallback(RGFW_jsButtonfunc func);
908/*! set callback for a joystick axis mov event returns previous callback function (if it was set) */
909RGFWDEF RGFW_jsAxisfunc RGFW_setjsAxisCallback(RGFW_jsAxisfunc func);
910
911/** @} */
912
913/** * @defgroup Threads
914* @{ */
915
916#ifndef RGFW_NO_THREADS
917 /*! threading functions*/
918
919 /*! NOTE! (for X11/linux) : if you define a window in a thread, it must be run after the original thread's window is created or else there will be a memory error */
920 /*
921 I'd suggest you use sili's threading functions instead
922 if you're going to use sili
923 which is a good idea generally
924 */
925
926 #if defined(__unix__) || defined(__APPLE__) || defined(RGFW_WEBASM)
927 typedef void* (* RGFW_threadFunc_ptr)(void*);
928 #else
929 typedef DWORD (__stdcall *RGFW_threadFunc_ptr) (LPVOID lpThreadParameter);
930 #endif
931
932 RGFWDEF RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args); /*!< create a thread*/
933 RGFWDEF void RGFW_cancelThread(RGFW_thread thread); /*!< cancels a thread*/
934 RGFWDEF void RGFW_joinThread(RGFW_thread thread); /*!< join thread to current thread */
935 RGFWDEF void RGFW_setThreadPriority(RGFW_thread thread, u8 priority); /*!< sets the priority priority */
936#endif
937
938/** @} */
939
940/** * @defgroup joystick
941* @{ */
942
943/*! joystick count starts at 0*/
944/*!< register joystick to window based on a number (the number is based on when it was connected eg. /dev/js0)*/
945RGFWDEF u16 RGFW_registerJoystick(RGFW_window* win, i32 jsNumber);
946RGFWDEF u16 RGFW_registerJoystickF(RGFW_window* win, char* file);
947
948RGFWDEF u32 RGFW_isPressedJS(RGFW_window* win, u16 controller, u8 button);
949
950/** @} */
951
952/** * @defgroup graphics_API
953* @{ */
954
955/*!< make the window the current opengl drawing context
956
957 NOTE:
958 if you want to switch the graphics context's thread,
959 you have to run RGFW_window_makeCurrent(NULL); on the old thread
960 then RGFW_window_makeCurrent(valid_window) on the new thread
961*/
962RGFWDEF void RGFW_window_makeCurrent(RGFW_window* win);
963
964/*< updates fps / sets fps to cap (must by ran manually by the user at the end of a frame), returns current fps */
965RGFWDEF u32 RGFW_window_checkFPS(RGFW_window* win, u32 fpsCap);
966
967/* supports openGL, directX, OSMesa, EGL and software rendering */
968RGFWDEF void RGFW_window_swapBuffers(RGFW_window* win); /*!< swap the rendering buffer */
969RGFWDEF void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval);
970
971RGFWDEF void RGFW_window_setGPURender(RGFW_window* win, i8 set);
972RGFWDEF void RGFW_window_setCPURender(RGFW_window* win, i8 set);
973
974/*! native API functions */
975#if defined(RGFW_OPENGL) || defined(RGFW_EGL)
976 /*! OpenGL init hints */
977 RGFWDEF void RGFW_setGLStencil(i32 stencil); /*!< set stencil buffer bit size (8 by default) */
978 RGFWDEF void RGFW_setGLSamples(i32 samples); /*!< set number of sampiling buffers (4 by default) */
979 RGFWDEF void RGFW_setGLStereo(i32 stereo); /*!< use GL_STEREO (GL_FALSE by default) */
980 RGFWDEF void RGFW_setGLAuxBuffers(i32 auxBuffers); /*!< number of aux buffers (0 by default) */
981
982 /*! which profile to use for the opengl verion */
983 typedef RGFW_ENUM(u8, RGFW_GL_profile) { RGFW_GL_CORE = 0, RGFW_GL_COMPATIBILITY };
984 /*! Set OpenGL version hint (core or compatibility profile)*/
985 RGFWDEF void RGFW_setGLVersion(RGFW_GL_profile profile, i32 major, i32 minor);
986 RGFWDEF void RGFW_setDoubleBuffer(b8 useDoubleBuffer);
987 RGFWDEF void* RGFW_getProcAddress(const char* procname); /*!< get native opengl proc address */
988 RGFWDEF void RGFW_window_makeCurrent_OpenGL(RGFW_window* win); /*!< to be called by RGFW_window_makeCurrent */
989#elif defined(RGFW_DIRECTX)
990 typedef struct {
991 IDXGIFactory* pFactory;
992 IDXGIAdapter* pAdapter;
993 ID3D11Device* pDevice;
994 ID3D11DeviceContext* pDeviceContext;
995 } RGFW_directXinfo;
996
997 /*
998 RGFW stores a global instance of RGFW_directXinfo,
999 you can use this function to get a pointer the instance
1000 */
1001 RGFWDEF RGFW_directXinfo* RGFW_getDirectXInfo(void);
1002#endif
1003
1004/** @} */
1005
1006/** * @defgroup Supporting
1007* @{ */
1008RGFWDEF u64 RGFW_getTime(void); /*!< get time in seconds */
1009RGFWDEF u64 RGFW_getTimeNS(void); /*!< get time in nanoseconds */
1010RGFWDEF void RGFW_sleep(u64 milisecond); /*!< sleep for a set time */
1011
1012/*!
1013 key codes and mouse icon enums
1014*/
1015
1016typedef RGFW_ENUM(u8, RGFW_Key) {
1017 RGFW_KEY_NULL = 0,
1018 RGFW_Escape,
1019 RGFW_F1,
1020 RGFW_F2,
1021 RGFW_F3,
1022 RGFW_F4,
1023 RGFW_F5,
1024 RGFW_F6,
1025 RGFW_F7,
1026 RGFW_F8,
1027 RGFW_F9,
1028 RGFW_F10,
1029 RGFW_F11,
1030 RGFW_F12,
1031
1032 RGFW_Backtick,
1033
1034 RGFW_0,
1035 RGFW_1,
1036 RGFW_2,
1037 RGFW_3,
1038 RGFW_4,
1039 RGFW_5,
1040 RGFW_6,
1041 RGFW_7,
1042 RGFW_8,
1043 RGFW_9,
1044
1045 RGFW_Minus,
1046 RGFW_Equals,
1047 RGFW_BackSpace,
1048 RGFW_Tab,
1049 RGFW_CapsLock,
1050 RGFW_ShiftL,
1051 RGFW_ControlL,
1052 RGFW_AltL,
1053 RGFW_SuperL,
1054 RGFW_ShiftR,
1055 RGFW_ControlR,
1056 RGFW_AltR,
1057 RGFW_SuperR,
1058 RGFW_Space,
1059
1060 RGFW_a,
1061 RGFW_b,
1062 RGFW_c,
1063 RGFW_d,
1064 RGFW_e,
1065 RGFW_f,
1066 RGFW_g,
1067 RGFW_h,
1068 RGFW_i,
1069 RGFW_j,
1070 RGFW_k,
1071 RGFW_l,
1072 RGFW_m,
1073 RGFW_n,
1074 RGFW_o,
1075 RGFW_p,
1076 RGFW_q,
1077 RGFW_r,
1078 RGFW_s,
1079 RGFW_t,
1080 RGFW_u,
1081 RGFW_v,
1082 RGFW_w,
1083 RGFW_x,
1084 RGFW_y,
1085 RGFW_z,
1086
1087 RGFW_Period,
1088 RGFW_Comma,
1089 RGFW_Slash,
1090 RGFW_Bracket,
1091 RGFW_CloseBracket,
1092 RGFW_Semicolon,
1093 RGFW_Return,
1094 RGFW_Quote,
1095 RGFW_BackSlash,
1096
1097 RGFW_Up,
1098 RGFW_Down,
1099 RGFW_Left,
1100 RGFW_Right,
1101
1102 RGFW_Delete,
1103 RGFW_Insert,
1104 RGFW_End,
1105 RGFW_Home,
1106 RGFW_PageUp,
1107 RGFW_PageDown,
1108
1109 RGFW_Numlock,
1110 RGFW_KP_Slash,
1111 RGFW_Multiply,
1112 RGFW_KP_Minus,
1113 RGFW_KP_1,
1114 RGFW_KP_2,
1115 RGFW_KP_3,
1116 RGFW_KP_4,
1117 RGFW_KP_5,
1118 RGFW_KP_6,
1119 RGFW_KP_7,
1120 RGFW_KP_8,
1121 RGFW_KP_9,
1122 RGFW_KP_0,
1123 RGFW_KP_Period,
1124 RGFW_KP_Return,
1125
1126 final_key,
1127};
1128
1129
1130typedef RGFW_ENUM(u8, RGFW_mouseIcons) {
1131 RGFW_MOUSE_NORMAL = 0,
1132 RGFW_MOUSE_ARROW,
1133 RGFW_MOUSE_IBEAM,
1134 RGFW_MOUSE_CROSSHAIR,
1135 RGFW_MOUSE_POINTING_HAND,
1136 RGFW_MOUSE_RESIZE_EW,
1137 RGFW_MOUSE_RESIZE_NS,
1138 RGFW_MOUSE_RESIZE_NWSE,
1139 RGFW_MOUSE_RESIZE_NESW,
1140 RGFW_MOUSE_RESIZE_ALL,
1141 RGFW_MOUSE_NOT_ALLOWED,
1142};
1143
1144/** @} */
1145
1146#endif /* RGFW_HEADER */
1147
1148/*
1149Example to get you started :
1150
1151linux : gcc main.c -lX11 -lXcursor -lGL
1152windows : gcc main.c -lopengl32 -lshell32 -lgdi32
1153macos : gcc main.c -framework Foundation -framework AppKit -framework OpenGL -framework CoreVideo
1154
1155#define RGFW_IMPLEMENTATION
1156#include "RGFW.h"
1157
1158u8 icon[4 * 3 * 3] = {0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF};
1159
1160int main() {
1161 RGFW_window* win = RGFW_createWindow("name", RGFW_RECT(500, 500, 500, 500), (u64)0);
1162
1163 RGFW_window_setIcon(win, icon, RGFW_AREA(3, 3), 4);
1164
1165 for (;;) {
1166 RGFW_window_checkEvent(win); // NOTE: checking events outside of a while loop may cause input lag
1167 if (win->event.type == RGFW_quit || RGFW_isPressed(win, RGFW_Escape))
1168 break;
1169
1170 RGFW_window_swapBuffers(win);
1171
1172 glClearColor(0xFF, 0XFF, 0xFF, 0xFF);
1173 glClear(GL_COLOR_BUFFER_BIT);
1174 }
1175
1176 RGFW_window_close(win);
1177}
1178
1179 compiling :
1180
1181 if you wish to compile the library all you have to do is create a new file with this in it
1182
1183 rgfw.c
1184 #define RGFW_IMPLEMENTATION
1185 #include "RGFW.h"
1186
1187 then you can use gcc (or whatever compile you wish to use) to compile the library into object file
1188
1189 ex. gcc -c RGFW.c -fPIC
1190
1191 after you compile the library into an object file, you can also turn the object file into an static or shared library
1192
1193 (commands ar and gcc can be replaced with whatever equivalent your system uses)
1194 static : ar rcs RGFW.a RGFW.o
1195 shared :
1196 windows:
1197 gcc -shared RGFW.o -lwinmm -lopengl32 -lshell32 -lgdi32 -o RGFW.dll
1198 linux:
1199 gcc -shared RGFW.o -lX11 -lXcursor -lGL -lXrandr -o RGFW.so
1200 macos:
1201 gcc -shared RGFW.o -framework Foundation -framework AppKit -framework OpenGL -framework CoreVideo
1202*/
1203
1204#ifdef RGFW_X11
1205 #define RGFW_OS_BASED_VALUE(l, w, m, h, ww) l
1206#elif defined(RGFW_WINDOWS)
1207 #define RGFW_OS_BASED_VALUE(l, w, m, h, ww) w
1208#elif defined(RGFW_MACOS)
1209 #define RGFW_OS_BASED_VALUE(l, w, m, h, ww) m
1210#elif defined(RGFW_WEBASM)
1211 #define RGFW_OS_BASED_VALUE(l, w, m, h, ww) h
1212#elif defined(RGFW_WAYLAND)
1213 #define RGFW_OS_BASED_VALUE(l, w, m, h, ww) ww
1214#endif
1215
1216
1217#ifdef RGFW_IMPLEMENTATION
1218
1219#include <stdio.h>
1220#include <string.h>
1221#include <math.h>
1222#include <assert.h>
1223
1224/*
1225RGFW_IMPLEMENTATION starts with generic RGFW defines
1226
1227This is the start of keycode data
1228
1229 Why not use macros instead of the numbers itself?
1230 Windows -> Not all virtual keys are macros (VK_0 - VK_1, VK_a - VK_z)
1231 Linux -> Only symcodes are values, (XK_0 - XK_1, XK_a - XK_z) are larger than 0xFF00, I can't find any way to work with them without making the array an unreasonable size
1232 MacOS -> windows and linux already don't have keycodes as macros, so there's no point
1233*/
1234
1235
1236
1237/*
1238 the c++ compiler doesn't support setting up an array like,
1239 we'll have to do it during runtime using a function & this messy setup
1240*/
1241#ifndef __cplusplus
1242#define RGFW_NEXT ,
1243#define RGFW_MAP
1244#else
1245#define RGFW_NEXT ;
1246#define RGFW_MAP RGFW_keycodes
1247#endif
1248
1249#ifdef RGFW_WAYLAND
1250#include <linux/input-event-codes.h>
1251#endif
1252
1253u8 RGFW_keycodes [RGFW_OS_BASED_VALUE(136, 337, 128, DOM_VK_WIN_OEM_CLEAR + 1, 130)] = {
1254#ifdef __cplusplus
1255 0
1256};
1257void RGFW_init_keys(void) {
1258#endif
1259 RGFW_MAP [RGFW_OS_BASED_VALUE(49, 192, 50, DOM_VK_BACK_QUOTE, KEY_GRAVE)] = RGFW_Backtick RGFW_NEXT
1260
1261 RGFW_MAP [RGFW_OS_BASED_VALUE(19, 0x30, 29, DOM_VK_0, KEY_0)] = RGFW_0 RGFW_NEXT
1262 RGFW_MAP [RGFW_OS_BASED_VALUE(10, 0x31, 18, DOM_VK_1, KEY_1)] = RGFW_1 RGFW_NEXT
1263 RGFW_MAP [RGFW_OS_BASED_VALUE(11, 0x32, 19, DOM_VK_2, KEY_2)] = RGFW_2 RGFW_NEXT
1264 RGFW_MAP [RGFW_OS_BASED_VALUE(12, 0x33, 20, DOM_VK_3, KEY_3)] = RGFW_3 RGFW_NEXT
1265 RGFW_MAP [RGFW_OS_BASED_VALUE(13, 0x34, 21, DOM_VK_4, KEY_4)] = RGFW_4 RGFW_NEXT
1266 RGFW_MAP [RGFW_OS_BASED_VALUE(14, 0x35, 23, DOM_VK_5, KEY_5)] = RGFW_5 RGFW_NEXT
1267 RGFW_MAP [RGFW_OS_BASED_VALUE(15, 0x36, 22, DOM_VK_6, KEY_6)] = RGFW_6 RGFW_NEXT
1268 RGFW_MAP [RGFW_OS_BASED_VALUE(16, 0x37, 26, DOM_VK_7, KEY_7)] = RGFW_7 RGFW_NEXT
1269 RGFW_MAP [RGFW_OS_BASED_VALUE(17, 0x38, 28, DOM_VK_8, KEY_8)] = RGFW_8 RGFW_NEXT
1270 RGFW_MAP [RGFW_OS_BASED_VALUE(18, 0x39, 25, DOM_VK_9, KEY_9)] = RGFW_9,
1271
1272 RGFW_MAP [RGFW_OS_BASED_VALUE(65, 0x20, 49, DOM_VK_SPACE, KEY_SPACE)] = RGFW_Space,
1273
1274 RGFW_MAP [RGFW_OS_BASED_VALUE(38, 0x41, 0, DOM_VK_A, KEY_A)] = RGFW_a RGFW_NEXT
1275 RGFW_MAP [RGFW_OS_BASED_VALUE(56, 0x42, 11, DOM_VK_B, KEY_B)] = RGFW_b RGFW_NEXT
1276 RGFW_MAP [RGFW_OS_BASED_VALUE(54, 0x43, 8, DOM_VK_C, KEY_C)] = RGFW_c RGFW_NEXT
1277 RGFW_MAP [RGFW_OS_BASED_VALUE(40, 0x44, 2, DOM_VK_D, KEY_D)] = RGFW_d RGFW_NEXT
1278 RGFW_MAP [RGFW_OS_BASED_VALUE(26, 0x45, 14, DOM_VK_E, KEY_E)] = RGFW_e RGFW_NEXT
1279 RGFW_MAP [RGFW_OS_BASED_VALUE(41, 0x46, 3, DOM_VK_F, KEY_F)] = RGFW_f RGFW_NEXT
1280 RGFW_MAP [RGFW_OS_BASED_VALUE(42, 0x47, 5, DOM_VK_G, KEY_G)] = RGFW_g RGFW_NEXT
1281 RGFW_MAP [RGFW_OS_BASED_VALUE(43, 0x48, 4, DOM_VK_H, KEY_H)] = RGFW_h RGFW_NEXT
1282 RGFW_MAP [RGFW_OS_BASED_VALUE(31, 0x49, 34, DOM_VK_I, KEY_I)] = RGFW_i RGFW_NEXT
1283 RGFW_MAP [RGFW_OS_BASED_VALUE(44, 0x4A, 38, DOM_VK_J, KEY_J)] = RGFW_j RGFW_NEXT
1284 RGFW_MAP [RGFW_OS_BASED_VALUE(45, 0x4B, 40, DOM_VK_K, KEY_K)] = RGFW_k RGFW_NEXT
1285 RGFW_MAP [RGFW_OS_BASED_VALUE(46, 0x4C, 37, DOM_VK_L, KEY_L)] = RGFW_l RGFW_NEXT
1286 RGFW_MAP [RGFW_OS_BASED_VALUE(58, 0x4D, 46, DOM_VK_M, KEY_M)] = RGFW_m RGFW_NEXT
1287 RGFW_MAP [RGFW_OS_BASED_VALUE(57, 0x4E, 45, DOM_VK_N, KEY_N)] = RGFW_n RGFW_NEXT
1288 RGFW_MAP [RGFW_OS_BASED_VALUE(32, 0x4F, 31, DOM_VK_O, KEY_O)] = RGFW_o RGFW_NEXT
1289 RGFW_MAP [RGFW_OS_BASED_VALUE(33, 0x50, 35, DOM_VK_P, KEY_P)] = RGFW_p RGFW_NEXT
1290 RGFW_MAP [RGFW_OS_BASED_VALUE(24, 0x51, 12, DOM_VK_Q, KEY_Q)] = RGFW_q RGFW_NEXT
1291 RGFW_MAP [RGFW_OS_BASED_VALUE(27, 0x52, 15, DOM_VK_R, KEY_R)] = RGFW_r RGFW_NEXT
1292 RGFW_MAP [RGFW_OS_BASED_VALUE(39, 0x53, 1, DOM_VK_S, KEY_S)] = RGFW_s RGFW_NEXT
1293 RGFW_MAP [RGFW_OS_BASED_VALUE(28, 0x54, 17, DOM_VK_T, KEY_T)] = RGFW_t RGFW_NEXT
1294 RGFW_MAP [RGFW_OS_BASED_VALUE(30, 0x55, 32, DOM_VK_U, KEY_U)] = RGFW_u RGFW_NEXT
1295 RGFW_MAP [RGFW_OS_BASED_VALUE(55, 0x56, 9, DOM_VK_V, KEY_V)] = RGFW_v RGFW_NEXT
1296 RGFW_MAP [RGFW_OS_BASED_VALUE(25, 0x57, 13, DOM_VK_W, KEY_W)] = RGFW_w RGFW_NEXT
1297 RGFW_MAP [RGFW_OS_BASED_VALUE(53, 0x58, 7, DOM_VK_X, KEY_X)] = RGFW_x RGFW_NEXT
1298 RGFW_MAP [RGFW_OS_BASED_VALUE(29, 0x59, 16, DOM_VK_Y, KEY_Y)] = RGFW_y RGFW_NEXT
1299 RGFW_MAP [RGFW_OS_BASED_VALUE(52, 0x5A, 6, DOM_VK_Z, KEY_Z)] = RGFW_z,
1300
1301 RGFW_MAP [RGFW_OS_BASED_VALUE(60, 190, 47, DOM_VK_PERIOD, KEY_DOT)] = RGFW_Period RGFW_NEXT
1302 RGFW_MAP [RGFW_OS_BASED_VALUE(59, 188, 43, DOM_VK_COMMA, KEY_COMMA)] = RGFW_Comma RGFW_NEXT
1303 RGFW_MAP [RGFW_OS_BASED_VALUE(61, 191, 44, DOM_VK_SLASH, KEY_SLASH)] = RGFW_Slash RGFW_NEXT
1304 RGFW_MAP [RGFW_OS_BASED_VALUE(34, 219, 33, DOM_VK_OPEN_BRACKET, KEY_LEFTBRACE)] = RGFW_Bracket RGFW_NEXT
1305 RGFW_MAP [RGFW_OS_BASED_VALUE(35, 221, 30, DOM_VK_CLOSE_BRACKET, KEY_RIGHTBRACE)] = RGFW_CloseBracket RGFW_NEXT
1306 RGFW_MAP [RGFW_OS_BASED_VALUE(47, 186, 41, DOM_VK_SEMICOLON, KEY_SEMICOLON)] = RGFW_Semicolon RGFW_NEXT
1307 RGFW_MAP [RGFW_OS_BASED_VALUE(48, 222, 39, DOM_VK_QUOTE, KEY_APOSTROPHE)] = RGFW_Quote RGFW_NEXT
1308 RGFW_MAP [RGFW_OS_BASED_VALUE(51, 322, 42, DOM_VK_BACK_SLASH, KEY_BACKSLASH)] = RGFW_BackSlash,
1309
1310 RGFW_MAP [RGFW_OS_BASED_VALUE(36, 0x0D, 36, DOM_VK_RETURN, KEY_ENTER)] = RGFW_Return RGFW_NEXT
1311 RGFW_MAP [RGFW_OS_BASED_VALUE(119, 0x2E, 118, DOM_VK_DELETE, KEY_DELETE)] = RGFW_Delete RGFW_NEXT
1312 RGFW_MAP [RGFW_OS_BASED_VALUE(77, 0x90, 72, DOM_VK_NUM_LOCK, KEY_NUMLOCK)] = RGFW_Numlock RGFW_NEXT
1313 RGFW_MAP [RGFW_OS_BASED_VALUE(106, 0x6F, 82, DOM_VK_DIVIDE, KEY_KPSLASH)] = RGFW_KP_Slash RGFW_NEXT
1314 RGFW_MAP [RGFW_OS_BASED_VALUE(63, 0x6A, 76, DOM_VK_MULTIPLY, KEY_KPASTERISK)] = RGFW_Multiply RGFW_NEXT
1315 RGFW_MAP [RGFW_OS_BASED_VALUE(82, 0x6D, 67, DOM_VK_SUBTRACT, KEY_KPMINUS)] = RGFW_KP_Minus RGFW_NEXT
1316 RGFW_MAP [RGFW_OS_BASED_VALUE(87, 0x61, 84, DOM_VK_NUMPAD1, KEY_KP1)] = RGFW_KP_1 RGFW_NEXT
1317 RGFW_MAP [RGFW_OS_BASED_VALUE(88, 0x62, 85, DOM_VK_NUMPAD2, KEY_KP2)] = RGFW_KP_2 RGFW_NEXT
1318 RGFW_MAP [RGFW_OS_BASED_VALUE(89, 0x63, 86, DOM_VK_NUMPAD3, KEY_KP3)] = RGFW_KP_3 RGFW_NEXT
1319 RGFW_MAP [RGFW_OS_BASED_VALUE(83, 0x64, 87, DOM_VK_NUMPAD4, KEY_KP4)] = RGFW_KP_4 RGFW_NEXT
1320 RGFW_MAP [RGFW_OS_BASED_VALUE(84, 0x65, 88, DOM_VK_NUMPAD5, KEY_KP5)] = RGFW_KP_5 RGFW_NEXT
1321 RGFW_MAP [RGFW_OS_BASED_VALUE(85, 0x66, 89, DOM_VK_NUMPAD6, KEY_KP6)] = RGFW_KP_6 RGFW_NEXT
1322 RGFW_MAP [RGFW_OS_BASED_VALUE(79, 0x67, 90, DOM_VK_NUMPAD7, KEY_KP7)] = RGFW_KP_7 RGFW_NEXT
1323 RGFW_MAP [RGFW_OS_BASED_VALUE(80, 0x68, 92, DOM_VK_NUMPAD8, KEY_KP8)] = RGFW_KP_8 RGFW_NEXT
1324 RGFW_MAP [RGFW_OS_BASED_VALUE(81, 0x69, 93, DOM_VK_NUMPAD9, KEY_KP9)] = RGFW_KP_9 RGFW_NEXT
1325 RGFW_MAP [RGFW_OS_BASED_VALUE(90, 0x60, 83, DOM_VK_NUMPAD0, KEY_KP0)] = RGFW_KP_0 RGFW_NEXT
1326 RGFW_MAP [RGFW_OS_BASED_VALUE(91, 0x6E, 65, DOM_VK_DECIMAL, KEY_KPDOT)] = RGFW_KP_Period RGFW_NEXT
1327 RGFW_MAP [RGFW_OS_BASED_VALUE(104, 0x92, 77, 0, KEY_KPENTER)] = RGFW_KP_Return,
1328
1329 RGFW_MAP [RGFW_OS_BASED_VALUE(20, 189, 27, DOM_VK_HYPHEN_MINUS, KEY_MINUS)] = RGFW_Minus RGFW_NEXT
1330 RGFW_MAP [RGFW_OS_BASED_VALUE(21, 187, 24, DOM_VK_EQUALS, KEY_EQUAL)] = RGFW_Equals RGFW_NEXT
1331 RGFW_MAP [RGFW_OS_BASED_VALUE(22, 8, 51, DOM_VK_BACK_SPACE, KEY_BACKSPACE)] = RGFW_BackSpace RGFW_NEXT
1332 RGFW_MAP [RGFW_OS_BASED_VALUE(23, 0x09, 48, DOM_VK_TAB, KEY_TAB)] = RGFW_Tab RGFW_NEXT
1333 RGFW_MAP [RGFW_OS_BASED_VALUE(66, 20, 57, DOM_VK_CAPS_LOCK, KEY_CAPSLOCK)] = RGFW_CapsLock RGFW_NEXT
1334 RGFW_MAP [RGFW_OS_BASED_VALUE(50, 0x10, 56, DOM_VK_SHIFT, KEY_LEFTSHIFT)] = RGFW_ShiftL RGFW_NEXT
1335 RGFW_MAP [RGFW_OS_BASED_VALUE(37, 0x11, 59, DOM_VK_CONTROL, KEY_LEFTCTRL)] = RGFW_ControlL RGFW_NEXT
1336 RGFW_MAP [RGFW_OS_BASED_VALUE(64,0x12, 58, DOM_VK_ALT, KEY_LEFTALT)] = RGFW_AltL RGFW_NEXT
1337 RGFW_MAP [RGFW_OS_BASED_VALUE(133, 0x5B, 55, DOM_VK_WIN, KEY_LEFTMETA)] = RGFW_SuperL,
1338
1339 #if !defined(RGFW_WINDOWS) && !defined(RGFW_MACOS) && !defined(RGFW_WEBASM)
1340 RGFW_MAP [RGFW_OS_BASED_VALUE(105, 0x11, 59, 0, KEY_RIGHTCTRL)] = RGFW_ControlR RGFW_NEXT
1341 RGFW_MAP [RGFW_OS_BASED_VALUE(135, 0xA4, 55, 0, KEY_RIGHTMETA)] = RGFW_SuperR,
1342 RGFW_MAP [RGFW_OS_BASED_VALUE(62, 0x5C, 56, 0, KEY_RIGHTSHIFT)] = RGFW_ShiftR RGFW_NEXT
1343 RGFW_MAP [RGFW_OS_BASED_VALUE(108, 165, 58, 0, KEY_RIGHTALT)] = RGFW_AltR,
1344 #endif
1345
1346 RGFW_MAP [RGFW_OS_BASED_VALUE(67, 0x70, 127, DOM_VK_F1, KEY_F1)] = RGFW_F1 RGFW_NEXT
1347 RGFW_MAP [RGFW_OS_BASED_VALUE(68, 0x71, 121, DOM_VK_F2, KEY_F2)] = RGFW_F2 RGFW_NEXT
1348 RGFW_MAP [RGFW_OS_BASED_VALUE(69, 0x72, 100, DOM_VK_F3, KEY_F3)] = RGFW_F3 RGFW_NEXT
1349 RGFW_MAP [RGFW_OS_BASED_VALUE(70, 0x73, 119, DOM_VK_F4, KEY_F4)] = RGFW_F4 RGFW_NEXT
1350 RGFW_MAP [RGFW_OS_BASED_VALUE(71, 0x74, 97, DOM_VK_F5, KEY_F5)] = RGFW_F5 RGFW_NEXT
1351 RGFW_MAP [RGFW_OS_BASED_VALUE(72, 0x75, 98, DOM_VK_F6, KEY_F6)] = RGFW_F6 RGFW_NEXT
1352 RGFW_MAP [RGFW_OS_BASED_VALUE(73, 0x76, 99, DOM_VK_F7, KEY_F7)] = RGFW_F7 RGFW_NEXT
1353 RGFW_MAP [RGFW_OS_BASED_VALUE(74, 0x77, 101, DOM_VK_F8, KEY_F8)] = RGFW_F8 RGFW_NEXT
1354 RGFW_MAP [RGFW_OS_BASED_VALUE(75, 0x78, 102, DOM_VK_F9, KEY_F9)] = RGFW_F9 RGFW_NEXT
1355 RGFW_MAP [RGFW_OS_BASED_VALUE(76, 0x79, 110, DOM_VK_F10, KEY_F10)] = RGFW_F10 RGFW_NEXT
1356 RGFW_MAP [RGFW_OS_BASED_VALUE(95, 0x7A, 104, DOM_VK_F11, KEY_F11)] = RGFW_F11 RGFW_NEXT
1357 RGFW_MAP [RGFW_OS_BASED_VALUE(96, 0x7B, 112, DOM_VK_F12, KEY_F12)] = RGFW_F12 RGFW_NEXT
1358 RGFW_MAP [RGFW_OS_BASED_VALUE(111, 0x26, 126, DOM_VK_UP, KEY_UP)] = RGFW_Up RGFW_NEXT
1359 RGFW_MAP [RGFW_OS_BASED_VALUE(116, 0x28, 125, DOM_VK_DOWN, KEY_DOWN)] = RGFW_Down RGFW_NEXT
1360 RGFW_MAP [RGFW_OS_BASED_VALUE(113, 0x25, 123, DOM_VK_LEFT, KEY_LEFT)] = RGFW_Left RGFW_NEXT
1361 RGFW_MAP [RGFW_OS_BASED_VALUE(114, 0x27, 124, DOM_VK_RIGHT, KEY_RIGHT)] = RGFW_Right RGFW_NEXT
1362 RGFW_MAP [RGFW_OS_BASED_VALUE(118, 0x2D, 115, DOM_VK_INSERT, KEY_INSERT)] = RGFW_Insert RGFW_NEXT
1363 RGFW_MAP [RGFW_OS_BASED_VALUE(115, 0x23, 120, DOM_VK_END, KEY_END)] = RGFW_End RGFW_NEXT
1364 RGFW_MAP [RGFW_OS_BASED_VALUE(112, 336, 117, DOM_VK_PAGE_UP, KEY_PAGEUP)] = RGFW_PageUp RGFW_NEXT
1365 RGFW_MAP [RGFW_OS_BASED_VALUE(117, 325, 122, DOM_VK_PAGE_DOWN, KEY_PAGEDOWN)] = RGFW_PageDown RGFW_NEXT
1366 RGFW_MAP [RGFW_OS_BASED_VALUE(9, 0x1B, 53, DOM_VK_ESCAPE, KEY_ESC)] = RGFW_Escape RGFW_NEXT
1367 RGFW_MAP [RGFW_OS_BASED_VALUE(110, 0x24, 116, DOM_VK_HOME, KEY_HOME)] = RGFW_Home RGFW_NEXT
1368#ifndef __cplusplus
1369};
1370#else
1371}
1372#endif
1373
1374#undef RGFW_NEXT
1375#undef RGFW_MAP
1376
1377typedef struct {
1378 b8 current : 1;
1379 b8 prev : 1;
1380} RGFW_keyState;
1381
1382RGFW_keyState RGFW_keyboard[final_key] = { {0, 0} };
1383
1384RGFWDEF u32 RGFW_apiKeyCodeToRGFW(u32 keycode);
1385
1386u32 RGFW_apiKeyCodeToRGFW(u32 keycode) {
1387 #ifdef __cplusplus
1388 if (RGFW_OS_BASED_VALUE(49, 192, 50, DOM_VK_BACK_QUOTE, KEY_GRAVE) != RGFW_Backtick) {
1389 RGFW_init_keys();
1390 }
1391 #endif
1392
1393 /* make sure the key isn't out of bounds */
1394 if (keycode > sizeof(RGFW_keycodes) / sizeof(u8))
1395 return 0;
1396
1397 return RGFW_keycodes[keycode];
1398}
1399
1400RGFWDEF void RGFW_resetKey(void);
1401void RGFW_resetKey(void) {
1402 size_t len = final_key; /*!< last_key == length */
1403
1404 size_t i; /*!< reset each previous state */
1405 for (i = 0; i < len; i++)
1406 RGFW_keyboard[i].prev = 0;
1407}
1408
1409b8 RGFW_shouldShift(u32 keycode, u8 lockState) {
1410 #define RGFW_xor(x, y) (( (x) && (!(y)) ) || ((y) && (!(x)) ))
1411 b8 caps4caps = (lockState & RGFW_CAPSLOCK) && ((keycode >= RGFW_a) && (keycode <= RGFW_z));
1412 b8 shouldShift = RGFW_xor((RGFW_isPressed(NULL, RGFW_ShiftL) || RGFW_isPressed(NULL, RGFW_ShiftR)), caps4caps);
1413 #undef RGFW_xor
1414
1415 return shouldShift;
1416}
1417
1418char RGFW_keyCodeToChar(u32 keycode, b8 shift) {
1419 static const char map[] = {
1420 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '`', '0', '1', '2', '3', '4', '5', '6', '7', '8',
1421 '9', '-', '=', 0, '\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
1422 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '.', ',', '/', '[', ']', ';', '\n', '\'', '\\',
1423 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '/', '*', '-', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '\n'
1424 };
1425
1426 static const char mapCaps[] = {
1427 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '~', ')', '!', '@', '#', '$', '%', '^', '&', '*',
1428 '(', '_', '+', 0, '0', 0, 0, 0, 0, 0, 0, 0, 0, 0, ' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
1429 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
1430 'X', 'Y', 'Z', '>', '<', '?', '{', '}', ':', '\n', '"', '|',
1431 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '?', '*', '-', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1432 };
1433
1434 if (shift == RGFW_FALSE)
1435 return map[keycode];
1436 return mapCaps[keycode];
1437}
1438
1439char RGFW_keyCodeToCharAuto(u32 keycode, u8 lockState) { return RGFW_keyCodeToChar(keycode, RGFW_shouldShift(keycode, lockState)); }
1440
1441/*
1442 this is the end of keycode data
1443*/
1444
1445/* joystick data */
1446u8 RGFW_jsPressed[4][16]; /*!< if a key is currently pressed or not (per joystick) */
1447
1448i32 RGFW_joysticks[4]; /*!< limit of 4 joysticks at a time */
1449u16 RGFW_joystickCount; /*!< the actual amount of joysticks */
1450
1451/*
1452 event callback defines start here
1453*/
1454
1455
1456/*
1457 These exist to avoid the
1458 if (func == NULL) check
1459 for (allegedly) better performance
1460*/
1461void RGFW_windowmovefuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); }
1462void RGFW_windowresizefuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); }
1463void RGFW_windowquitfuncEMPTY(RGFW_window* win) { RGFW_UNUSED(win); }
1464void RGFW_focusfuncEMPTY(RGFW_window* win, b8 inFocus) {RGFW_UNUSED(win); RGFW_UNUSED(inFocus);}
1465void RGFW_mouseNotifyfuncEMPTY(RGFW_window* win, RGFW_point point, b8 status) {RGFW_UNUSED(win); RGFW_UNUSED(point); RGFW_UNUSED(status);}
1466void RGFW_mouseposfuncEMPTY(RGFW_window* win, RGFW_point point) {RGFW_UNUSED(win); RGFW_UNUSED(point);}
1467void RGFW_dndInitfuncEMPTY(RGFW_window* win, RGFW_point point) {RGFW_UNUSED(win); RGFW_UNUSED(point);}
1468void RGFW_windowrefreshfuncEMPTY(RGFW_window* win) {RGFW_UNUSED(win); }
1469void RGFW_keyfuncEMPTY(RGFW_window* win, u32 keycode, char keyName[16], u8 lockState, b8 pressed) {RGFW_UNUSED(win); RGFW_UNUSED(keycode); RGFW_UNUSED(keyName); RGFW_UNUSED(lockState); RGFW_UNUSED(pressed);}
1470void RGFW_mousebuttonfuncEMPTY(RGFW_window* win, u8 button, double scroll, b8 pressed) {RGFW_UNUSED(win); RGFW_UNUSED(button); RGFW_UNUSED(scroll); RGFW_UNUSED(pressed);}
1471void RGFW_jsButtonfuncEMPTY(RGFW_window* win, u16 joystick, u8 button, b8 pressed){RGFW_UNUSED(win); RGFW_UNUSED(joystick); RGFW_UNUSED(button); RGFW_UNUSED(pressed); }
1472void RGFW_jsAxisfuncEMPTY(RGFW_window* win, u16 joystick, RGFW_point axis[2], u8 axisesCount){RGFW_UNUSED(win); RGFW_UNUSED(joystick); RGFW_UNUSED(axis); RGFW_UNUSED(axisesCount); }
1473
1474#ifdef RGFW_ALLOC_DROPFILES
1475void RGFW_dndfuncEMPTY(RGFW_window* win, char** droppedFiles, u32 droppedFilesCount) {RGFW_UNUSED(win); RGFW_UNUSED(droppedFiles); RGFW_UNUSED(droppedFilesCount);}
1476#else
1477void RGFW_dndfuncEMPTY(RGFW_window* win, char droppedFiles[RGFW_MAX_DROPS][RGFW_MAX_PATH], u32 droppedFilesCount) {RGFW_UNUSED(win); RGFW_UNUSED(droppedFiles); RGFW_UNUSED(droppedFilesCount);}
1478#endif
1479
1480RGFW_windowmovefunc RGFW_windowMoveCallback = RGFW_windowmovefuncEMPTY;
1481RGFW_windowresizefunc RGFW_windowResizeCallback = RGFW_windowresizefuncEMPTY;
1482RGFW_windowquitfunc RGFW_windowQuitCallback = RGFW_windowquitfuncEMPTY;
1483RGFW_mouseposfunc RGFW_mousePosCallback = RGFW_mouseposfuncEMPTY;
1484RGFW_windowrefreshfunc RGFW_windowRefreshCallback = RGFW_windowrefreshfuncEMPTY;
1485RGFW_focusfunc RGFW_focusCallback = RGFW_focusfuncEMPTY;
1486RGFW_mouseNotifyfunc RGFW_mouseNotifyCallBack = RGFW_mouseNotifyfuncEMPTY;
1487RGFW_dndfunc RGFW_dndCallback = RGFW_dndfuncEMPTY;
1488RGFW_dndInitfunc RGFW_dndInitCallback = RGFW_dndInitfuncEMPTY;
1489RGFW_keyfunc RGFW_keyCallback = RGFW_keyfuncEMPTY;
1490RGFW_mousebuttonfunc RGFW_mouseButtonCallback = RGFW_mousebuttonfuncEMPTY;
1491RGFW_jsButtonfunc RGFW_jsButtonCallback = RGFW_jsButtonfuncEMPTY;
1492RGFW_jsAxisfunc RGFW_jsAxisCallback = RGFW_jsAxisfuncEMPTY;
1493
1494void RGFW_window_checkEvents(RGFW_window* win, i32 waitMS) {
1495 RGFW_window_eventWait(win, waitMS);
1496
1497 while (RGFW_window_checkEvent(win) != NULL && RGFW_window_shouldClose(win) == 0) {
1498 if (win->event.type == RGFW_quit) return;
1499 }
1500
1501 #ifdef RGFW_WEBASM /* webasm needs to run the sleep function for asyncify */
1502 RGFW_sleep(0);
1503 #endif
1504}
1505
1506RGFW_windowmovefunc RGFW_setWindowMoveCallback(RGFW_windowmovefunc func) {
1507 RGFW_windowmovefunc prev = (RGFW_windowMoveCallback == RGFW_windowmovefuncEMPTY) ? NULL : RGFW_windowMoveCallback;
1508 RGFW_windowMoveCallback = func;
1509 return prev;
1510}
1511RGFW_windowresizefunc RGFW_setWindowResizeCallback(RGFW_windowresizefunc func) {
1512 RGFW_windowresizefunc prev = (RGFW_windowResizeCallback == RGFW_windowresizefuncEMPTY) ? NULL : RGFW_windowResizeCallback;
1513 RGFW_windowResizeCallback = func;
1514 return prev;
1515}
1516RGFW_windowquitfunc RGFW_setWindowQuitCallback(RGFW_windowquitfunc func) {
1517 RGFW_windowquitfunc prev = (RGFW_windowQuitCallback == RGFW_windowquitfuncEMPTY) ? NULL : RGFW_windowQuitCallback;
1518 RGFW_windowQuitCallback = func;
1519 return prev;
1520}
1521
1522RGFW_mouseposfunc RGFW_setMousePosCallback(RGFW_mouseposfunc func) {
1523 RGFW_mouseposfunc prev = (RGFW_mousePosCallback == RGFW_mouseposfuncEMPTY) ? NULL : RGFW_mousePosCallback;
1524 RGFW_mousePosCallback = func;
1525 return prev;
1526}
1527RGFW_windowrefreshfunc RGFW_setWindowRefreshCallback(RGFW_windowrefreshfunc func) {
1528 RGFW_windowrefreshfunc prev = (RGFW_windowRefreshCallback == RGFW_windowrefreshfuncEMPTY) ? NULL : RGFW_windowRefreshCallback;
1529 RGFW_windowRefreshCallback = func;
1530 return prev;
1531}
1532RGFW_focusfunc RGFW_setFocusCallback(RGFW_focusfunc func) {
1533 RGFW_focusfunc prev = (RGFW_focusCallback == RGFW_focusfuncEMPTY) ? NULL : RGFW_focusCallback;
1534 RGFW_focusCallback = func;
1535 return prev;
1536}
1537
1538RGFW_mouseNotifyfunc RGFW_setMouseNotifyCallBack(RGFW_mouseNotifyfunc func) {
1539 RGFW_mouseNotifyfunc prev = (RGFW_mouseNotifyCallBack == RGFW_mouseNotifyfuncEMPTY) ? NULL : RGFW_mouseNotifyCallBack;
1540 RGFW_mouseNotifyCallBack = func;
1541 return prev;
1542}
1543RGFW_dndfunc RGFW_setDndCallback(RGFW_dndfunc func) {
1544 RGFW_dndfunc prev = (RGFW_dndCallback == RGFW_dndfuncEMPTY) ? NULL : RGFW_dndCallback;
1545 RGFW_dndCallback = func;
1546 return prev;
1547}
1548RGFW_dndInitfunc RGFW_setDndInitCallback(RGFW_dndInitfunc func) {
1549 RGFW_dndInitfunc prev = (RGFW_dndInitCallback == RGFW_dndInitfuncEMPTY) ? NULL : RGFW_dndInitCallback;
1550 RGFW_dndInitCallback = func;
1551 return prev;
1552}
1553RGFW_keyfunc RGFW_setKeyCallback(RGFW_keyfunc func) {
1554 RGFW_keyfunc prev = (RGFW_keyCallback == RGFW_keyfuncEMPTY) ? NULL : RGFW_keyCallback;
1555 RGFW_keyCallback = func;
1556 return prev;
1557}
1558RGFW_mousebuttonfunc RGFW_setMouseButtonCallback(RGFW_mousebuttonfunc func) {
1559 RGFW_mousebuttonfunc prev = (RGFW_mouseButtonCallback == RGFW_mousebuttonfuncEMPTY) ? NULL : RGFW_mouseButtonCallback;
1560 RGFW_mouseButtonCallback = func;
1561 return prev;
1562}
1563RGFW_jsButtonfunc RGFW_setjsButtonCallback(RGFW_jsButtonfunc func) {
1564 RGFW_jsButtonfunc prev = (RGFW_jsButtonCallback == RGFW_jsButtonfuncEMPTY) ? NULL : RGFW_jsButtonCallback;
1565 RGFW_jsButtonCallback = func;
1566 return prev;
1567}
1568RGFW_jsAxisfunc RGFW_setjsAxisCallback(RGFW_jsAxisfunc func) {
1569 RGFW_jsAxisfunc prev = (RGFW_jsAxisCallback == RGFW_jsAxisfuncEMPTY) ? NULL : RGFW_jsAxisCallback;
1570 RGFW_jsAxisCallback = func;
1571 return prev;
1572}
1573/*
1574no more event call back defines
1575*/
1576
1577#define RGFW_ASSERT(check, str) {\
1578 if (!(check)) { \
1579 printf(str); \
1580 assert(check); \
1581 } \
1582}
1583
1584b8 RGFW_error = 0;
1585b8 RGFW_Error(void) { return RGFW_error; }
1586
1587#define SET_ATTRIB(a, v) { \
1588 assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
1589 attribs[index++] = a; \
1590 attribs[index++] = v; \
1591}
1592
1593RGFW_area RGFW_bufferSize = {0, 0};
1594void RGFW_setBufferSize(RGFW_area size) {
1595 RGFW_bufferSize = size;
1596}
1597
1598
1599RGFWDEF RGFW_window* RGFW_window_basic_init(RGFW_rect rect, u16 args);
1600
1601/* do a basic initialization for RGFW_window, this is to standard it for each OS */
1602RGFW_window* RGFW_window_basic_init(RGFW_rect rect, u16 args) {
1603 RGFW_window* win = (RGFW_window*) RGFW_MALLOC(sizeof(RGFW_window)); /*!< make a new RGFW struct */
1604
1605 /* clear out dnd info */
1606#ifdef RGFW_ALLOC_DROPFILES
1607 win->event.droppedFiles = (char**) RGFW_MALLOC(sizeof(char*) * RGFW_MAX_DROPS);
1608 u32 i;
1609 for (i = 0; i < RGFW_MAX_DROPS; i++)
1610 win->event.droppedFiles[i] = (char*) RGFW_CALLOC(RGFW_MAX_PATH, sizeof(char));
1611#endif
1612
1613 /* X11 requires us to have a display to get the screen size */
1614 #ifndef RGFW_X11
1615 RGFW_area screenR = RGFW_getScreenSize();
1616 #else
1617 win->src.display = XOpenDisplay(NULL);
1618 assert(win->src.display != NULL);
1619
1620 Screen* scrn = DefaultScreenOfDisplay((Display*)win->src.display);
1621 RGFW_area screenR = RGFW_AREA((u32)scrn->width, (u32)scrn->height);
1622 #endif
1623
1624 /* rect based the requested args */
1625 if (args & RGFW_FULLSCREEN)
1626 rect = RGFW_RECT(0, 0, screenR.w, screenR.h);
1627
1628 /* set and init the new window's data */
1629 win->r = rect;
1630 win->event.inFocus = 1;
1631 win->event.droppedFilesCount = 0;
1632 RGFW_joystickCount = 0;
1633 win->_winArgs = 0;
1634 win->event.lockState = 0;
1635
1636 return win;
1637}
1638
1639#ifndef RGFW_NO_MONITOR
1640void RGFW_window_scaleToMonitor(RGFW_window* win) {
1641 RGFW_monitor monitor = RGFW_window_getMonitor(win);
1642
1643 RGFW_window_resize(win, RGFW_AREA((u32)(monitor.scaleX * (float)win->r.w), (u32)(monitor.scaleX * (float)win->r.h)));
1644}
1645#endif
1646
1647RGFW_window* RGFW_root = NULL;
1648
1649
1650#define RGFW_HOLD_MOUSE (1L<<2) /*!< hold the moues still */
1651#define RGFW_MOUSE_LEFT (1L<<3) /* if mouse left the window */
1652
1653#ifdef RGFW_MACOS
1654RGFWDEF void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer);
1655RGFWDEF void* RGFW_cocoaGetLayer(void);
1656#endif
1657
1658char* RGFW_className = NULL;
1659void RGFW_setClassName(char* name) {
1660 RGFW_className = name;
1661}
1662
1663void RGFW_clipboardFree(char* str) { RGFW_FREE(str); }
1664
1665RGFW_keyState RGFW_mouseButtons[5] = { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1666
1667b8 RGFW_isMousePressed(RGFW_window* win, u8 button) {
1668 assert(win != NULL);
1669 return RGFW_mouseButtons[button].current && (win != NULL) && win->event.inFocus;
1670}
1671b8 RGFW_wasMousePressed(RGFW_window* win, u8 button) {
1672 assert(win != NULL);
1673 return RGFW_mouseButtons[button].prev && (win != NULL) && win->event.inFocus;
1674}
1675b8 RGFW_isMouseHeld(RGFW_window* win, u8 button) {
1676 return (RGFW_isMousePressed(win, button) && RGFW_wasMousePressed(win, button));
1677}
1678b8 RGFW_isMouseReleased(RGFW_window* win, u8 button) {
1679 return (!RGFW_isMousePressed(win, button) && RGFW_wasMousePressed(win, button));
1680}
1681
1682b8 RGFW_isPressed(RGFW_window* win, u8 key) {
1683 return RGFW_keyboard[key].current && (win == NULL || win->event.inFocus);
1684}
1685
1686b8 RGFW_wasPressed(RGFW_window* win, u8 key) {
1687 return RGFW_keyboard[key].prev && (win == NULL || win->event.inFocus);
1688}
1689
1690b8 RGFW_isHeld(RGFW_window* win, u8 key) {
1691 return (RGFW_isPressed(win, key) && RGFW_wasPressed(win, key));
1692}
1693
1694b8 RGFW_isClicked(RGFW_window* win, u8 key) {
1695 return (RGFW_wasPressed(win, key) && !RGFW_isPressed(win, key));
1696}
1697
1698b8 RGFW_isReleased(RGFW_window* win, u8 key) {
1699 return (!RGFW_isPressed(win, key) && RGFW_wasPressed(win, key));
1700}
1701
1702#if defined(RGFW_WINDOWS) && defined(RGFW_DIRECTX) /* defines for directX context*/
1703 RGFW_directXinfo RGFW_dxInfo;
1704 RGFW_directXinfo* RGFW_getDirectXInfo(void) { return &RGFW_dxInfo; }
1705#endif
1706
1707void RGFW_window_makeCurrent(RGFW_window* win) {
1708#if defined(RGFW_WINDOWS) && defined(RGFW_DIRECTX)
1709 if (win == NULL)
1710 RGFW_dxInfo.pDeviceContext->lpVtbl->OMSetRenderTargets(RGFW_dxInfo.pDeviceContext, 1, NULL, NULL);
1711 else
1712 RGFW_dxInfo.pDeviceContext->lpVtbl->OMSetRenderTargets(RGFW_dxInfo.pDeviceContext, 1, &win->src.renderTargetView, NULL);
1713#elif defined(RGFW_OPENGL)
1714 RGFW_window_makeCurrent_OpenGL(win);
1715#else
1716 RGFW_UNUSED(win)
1717#endif
1718}
1719
1720void RGFW_window_setGPURender(RGFW_window* win, i8 set) {
1721 if (!set && !(win->_winArgs & RGFW_NO_GPU_RENDER))
1722 win->_winArgs |= RGFW_NO_GPU_RENDER;
1723
1724 else if (set && win->_winArgs & RGFW_NO_GPU_RENDER)
1725 win->_winArgs ^= RGFW_NO_GPU_RENDER;
1726}
1727
1728void RGFW_window_setCPURender(RGFW_window* win, i8 set) {
1729 if (!set && !(win->_winArgs & RGFW_NO_CPU_RENDER))
1730 win->_winArgs |= RGFW_NO_CPU_RENDER;
1731
1732 else if (set && win->_winArgs & RGFW_NO_CPU_RENDER)
1733 win->_winArgs ^= RGFW_NO_CPU_RENDER;
1734}
1735
1736void RGFW_window_maximize(RGFW_window* win) {
1737 assert(win != NULL);
1738
1739 RGFW_area screen = RGFW_getScreenSize();
1740
1741 RGFW_window_move(win, RGFW_POINT(0, 0));
1742 RGFW_window_resize(win, screen);
1743}
1744
1745b8 RGFW_window_shouldClose(RGFW_window* win) {
1746 assert(win != NULL);
1747 return (win->event.type == RGFW_quit || RGFW_isPressed(win, RGFW_Escape));
1748}
1749
1750void RGFW_window_setShouldClose(RGFW_window* win) { win->event.type = RGFW_quit; RGFW_windowQuitCallback(win); }
1751
1752#ifndef RGFW_NO_MONITOR
1753 void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m) {
1754 RGFW_window_move(win, RGFW_POINT(m.rect.x + win->r.x, m.rect.y + win->r.y));
1755 }
1756#endif
1757
1758RGFWDEF void RGFW_captureCursor(RGFW_window* win, RGFW_rect);
1759RGFWDEF void RGFW_releaseCursor(RGFW_window* win);
1760
1761void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area) {
1762 if ((win->_winArgs & RGFW_HOLD_MOUSE))
1763 return;
1764
1765
1766 if (!area.w && !area.h)
1767 area = RGFW_AREA(win->r.w / 2, win->r.h / 2);
1768
1769 win->_winArgs |= RGFW_HOLD_MOUSE;
1770 RGFW_captureCursor(win, win->r);
1771 RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2)));
1772}
1773
1774void RGFW_window_mouseUnhold(RGFW_window* win) {
1775 if ((win->_winArgs & RGFW_HOLD_MOUSE)) {
1776 win->_winArgs ^= RGFW_HOLD_MOUSE;
1777
1778 RGFW_releaseCursor(win);
1779 }
1780}
1781
1782u32 RGFW_window_checkFPS(RGFW_window* win, u32 fpsCap) {
1783 u64 deltaTime = RGFW_getTimeNS() - win->event.frameTime;
1784
1785 u32 output_fps = 0;
1786 u64 fps = round(1e+9 / deltaTime);
1787 output_fps= fps;
1788
1789 if (fpsCap && fps > fpsCap) {
1790 u64 frameTimeNS = 1e+9 / fpsCap;
1791 u64 sleepTimeMS = (frameTimeNS - deltaTime) / 1e6;
1792
1793 if (sleepTimeMS > 0) {
1794 RGFW_sleep(sleepTimeMS);
1795 win->event.frameTime = 0;
1796 }
1797 }
1798
1799 win->event.frameTime = RGFW_getTimeNS();
1800
1801 if (fpsCap == 0)
1802 return (u32) output_fps;
1803
1804 deltaTime = RGFW_getTimeNS() - win->event.frameTime2;
1805 output_fps = round(1e+9 / deltaTime);
1806 win->event.frameTime2 = RGFW_getTimeNS();
1807
1808 return output_fps;
1809}
1810
1811u32 RGFW_isPressedJS(RGFW_window* win, u16 c, u8 button) {
1812 RGFW_UNUSED(win);
1813 return RGFW_jsPressed[c][button];
1814}
1815
1816#if defined(RGFW_X11) || defined(RGFW_WINDOWS)
1817 void RGFW_window_showMouse(RGFW_window* win, i8 show) {
1818 static u8 RGFW_blk[] = { 0, 0, 0, 0 };
1819 if (show == 0)
1820 RGFW_window_setMouse(win, RGFW_blk, RGFW_AREA(1, 1), 4);
1821 else
1822 RGFW_window_setMouseDefault(win);
1823 }
1824#endif
1825
1826RGFWDEF void RGFW_updateLockState(RGFW_window* win, b8 capital, b8 numlock);
1827void RGFW_updateLockState(RGFW_window* win, b8 capital, b8 numlock) {
1828 if (capital && !(win->event.lockState & RGFW_CAPSLOCK))
1829 win->event.lockState |= RGFW_CAPSLOCK;
1830 else if (!capital && (win->event.lockState & RGFW_CAPSLOCK))
1831 win->event.lockState ^= RGFW_CAPSLOCK;
1832
1833 if (numlock && !(win->event.lockState & RGFW_NUMLOCK))
1834 win->event.lockState |= RGFW_NUMLOCK;
1835 else if (!numlock && (win->event.lockState & RGFW_NUMLOCK))
1836 win->event.lockState ^= RGFW_NUMLOCK;
1837}
1838
1839#if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WEBASM) || defined(RGFW_WAYLAND)
1840 struct timespec;
1841
1842 int nanosleep(const struct timespec* duration, struct timespec* rem);
1843 int clock_gettime(clockid_t clk_id, struct timespec* tp);
1844 int setenv(const char *name, const char *value, int overwrite);
1845
1846 void RGFW_window_setDND(RGFW_window* win, b8 allow) {
1847 if (allow && !(win->_winArgs & RGFW_ALLOW_DND))
1848 win->_winArgs |= RGFW_ALLOW_DND;
1849
1850 else if (!allow && (win->_winArgs & RGFW_ALLOW_DND))
1851 win->_winArgs ^= RGFW_ALLOW_DND;
1852 }
1853#endif
1854
1855/*
1856 graphics API specific code (end of generic code)
1857 starts here
1858*/
1859
1860
1861/*
1862 OpenGL defines start here (Normal, EGL, OSMesa)
1863*/
1864
1865#if defined(RGFW_OPENGL) || defined(RGFW_EGL) || defined(RGFW_OSMESA)
1866 #ifdef RGFW_WINDOWS
1867 #define WIN32_LEAN_AND_MEAN
1868 #define OEMRESOURCE
1869 #include <windows.h>
1870 #endif
1871
1872 #if !defined(__APPLE__) && !defined(RGFW_NO_GL_HEADER)
1873 #include <GL/gl.h>
1874 #elif defined(__APPLE__)
1875 #ifndef GL_SILENCE_DEPRECATION
1876 #define GL_SILENCE_DEPRECATION
1877 #endif
1878 #include <OpenGL/gl.h>
1879 #include <OpenGL/OpenGL.h>
1880 #endif
1881
1882/* EGL, normal OpenGL only */
1883#if !defined(RGFW_OSMESA)
1884 i32 RGFW_majorVersion = 0, RGFW_minorVersion = 0;
1885 b8 RGFW_profile = RGFW_GL_CORE;
1886
1887 #ifndef RGFW_EGL
1888 i32 RGFW_STENCIL = 8, RGFW_SAMPLES = 4, RGFW_STEREO = 0, RGFW_AUX_BUFFERS = 0, RGFW_DOUBLE_BUFFER = 1;
1889 #else
1890 i32 RGFW_STENCIL = 0, RGFW_SAMPLES = 0, RGFW_STEREO = 0, RGFW_AUX_BUFFERS = 0, RGFW_DOUBLE_BUFFER = 1;
1891 #endif
1892
1893
1894 void RGFW_setGLStencil(i32 stencil) { RGFW_STENCIL = stencil; }
1895 void RGFW_setGLSamples(i32 samples) { RGFW_SAMPLES = samples; }
1896 void RGFW_setGLStereo(i32 stereo) { RGFW_STEREO = stereo; }
1897 void RGFW_setGLAuxBuffers(i32 auxBuffers) { RGFW_AUX_BUFFERS = auxBuffers; }
1898 void RGFW_setDoubleBuffer(b8 useDoubleBuffer) { RGFW_DOUBLE_BUFFER = useDoubleBuffer; }
1899
1900 void RGFW_setGLVersion(b8 profile, i32 major, i32 minor) {
1901 RGFW_profile = profile;
1902 RGFW_majorVersion = major;
1903 RGFW_minorVersion = minor;
1904 }
1905
1906/* OPENGL normal only (no EGL / OSMesa) */
1907#ifndef RGFW_EGL
1908
1909#define RGFW_GL_RENDER_TYPE RGFW_OS_BASED_VALUE(GLX_X_VISUAL_TYPE, 0x2003, 73, 0, 0)
1910 #define RGFW_GL_ALPHA_SIZE RGFW_OS_BASED_VALUE(GLX_ALPHA_SIZE, 0x201b, 11, 0, 0)
1911 #define RGFW_GL_DEPTH_SIZE RGFW_OS_BASED_VALUE(GLX_DEPTH_SIZE, 0x2022, 12, 0, 0)
1912 #define RGFW_GL_DOUBLEBUFFER RGFW_OS_BASED_VALUE(GLX_DOUBLEBUFFER, 0x2011, 5, 0, 0)
1913 #define RGFW_GL_STENCIL_SIZE RGFW_OS_BASED_VALUE(GLX_STENCIL_SIZE, 0x2023, 13, 0, 0)
1914 #define RGFW_GL_SAMPLES RGFW_OS_BASED_VALUE(GLX_SAMPLES, 0x2042, 55, 0, 0)
1915 #define RGFW_GL_STEREO RGFW_OS_BASED_VALUE(GLX_STEREO, 0x2012, 6, 0, 0)
1916 #define RGFW_GL_AUX_BUFFERS RGFW_OS_BASED_VALUE(GLX_AUX_BUFFERS, 0x2024, 7, 0, 0)
1917
1918#if defined(RGFW_X11) || defined(RGFW_WINDOWS)
1919 #define RGFW_GL_DRAW RGFW_OS_BASED_VALUE(GLX_X_RENDERABLE, 0x2001, 0, 0, 0)
1920 #define RGFW_GL_DRAW_TYPE RGFW_OS_BASED_VALUE(GLX_RENDER_TYPE, 0x2013, 0, 0, 0)
1921 #define RGFW_GL_FULL_FORMAT RGFW_OS_BASED_VALUE(GLX_TRUE_COLOR, 0x2027, 0, 0, 0)
1922 #define RGFW_GL_RED_SIZE RGFW_OS_BASED_VALUE(GLX_RED_SIZE, 0x2015, 0, 0, 0)
1923 #define RGFW_GL_GREEN_SIZE RGFW_OS_BASED_VALUE(GLX_GREEN_SIZE, 0x2017, 0, 0, 0)
1924 #define RGFW_GL_BLUE_SIZE RGFW_OS_BASED_VALUE(GLX_BLUE_SIZE, 0x2019, 0, 0, 0)
1925 #define RGFW_GL_USE_RGBA RGFW_OS_BASED_VALUE(GLX_RGBA_BIT, 0x202B, 0, 0, 0)
1926#endif
1927
1928#ifdef RGFW_WINDOWS
1929 #define WGL_SUPPORT_OPENGL_ARB 0x2010
1930 #define WGL_COLOR_BITS_ARB 0x2014
1931 #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
1932 #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
1933 #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
1934 #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
1935 #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
1936 #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
1937 #define WGL_SAMPLE_BUFFERS_ARB 0x2041
1938 #define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9
1939 #define WGL_PIXEL_TYPE_ARB 0x2013
1940 #define WGL_TYPE_RGBA_ARB 0x202B
1941
1942 #define WGL_TRANSPARENT_ARB 0x200A
1943#endif
1944
1945/* The window'ing api needs to know how to render the data we (or opengl) give it
1946 MacOS and Windows do this using a structure called a "pixel format"
1947 X11 calls it a "Visual"
1948 This function returns the attributes for the format we want */
1949 static u32* RGFW_initFormatAttribs(u32 useSoftware) {
1950 RGFW_UNUSED(useSoftware);
1951 static u32 attribs[] = {
1952 #if defined(RGFW_X11) || defined(RGFW_WINDOWS)
1953 RGFW_GL_RENDER_TYPE,
1954 RGFW_GL_FULL_FORMAT,
1955 #endif
1956 RGFW_GL_ALPHA_SIZE , 8,
1957 RGFW_GL_DEPTH_SIZE , 24,
1958 #if defined(RGFW_X11) || defined(RGFW_WINDOWS)
1959 RGFW_GL_DRAW, 1,
1960 RGFW_GL_RED_SIZE , 8,
1961 RGFW_GL_GREEN_SIZE , 8,
1962 RGFW_GL_BLUE_SIZE , 8,
1963 RGFW_GL_DRAW_TYPE , RGFW_GL_USE_RGBA,
1964 #endif
1965
1966 #ifdef RGFW_X11
1967 GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT,
1968 #endif
1969
1970 #ifdef RGFW_MACOS
1971 72,
1972 8, 24,
1973 #endif
1974
1975 #ifdef RGFW_WINDOWS
1976 WGL_SUPPORT_OPENGL_ARB, 1,
1977 WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
1978 WGL_COLOR_BITS_ARB, 32,
1979 #endif
1980
1981 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1982 };
1983
1984 size_t index = (sizeof(attribs) / sizeof(attribs[0])) - 13;
1985
1986 #define RGFW_GL_ADD_ATTRIB(attrib, attVal) \
1987 if (attVal) { \
1988 attribs[index] = attrib;\
1989 attribs[index + 1] = attVal;\
1990 index += 2;\
1991 }
1992
1993 RGFW_GL_ADD_ATTRIB(RGFW_GL_DOUBLEBUFFER, 1);
1994
1995 RGFW_GL_ADD_ATTRIB(RGFW_GL_STENCIL_SIZE, RGFW_STENCIL);
1996 RGFW_GL_ADD_ATTRIB(RGFW_GL_STEREO, RGFW_STEREO);
1997 RGFW_GL_ADD_ATTRIB(RGFW_GL_AUX_BUFFERS, RGFW_AUX_BUFFERS);
1998
1999#ifndef RGFW_X11
2000 RGFW_GL_ADD_ATTRIB(RGFW_GL_SAMPLES, RGFW_SAMPLES);
2001#endif
2002
2003#ifdef RGFW_MACOS
2004 if (useSoftware) {
2005 RGFW_GL_ADD_ATTRIB(70, kCGLRendererGenericFloatID);
2006 } else {
2007 attribs[index] = RGFW_GL_RENDER_TYPE;
2008 index += 1;
2009 }
2010#endif
2011
2012#ifdef RGFW_MACOS
2013 /* macOS has the surface attribs and the opengl attribs connected for some reason
2014 maybe this is to give macOS more control to limit openGL/the opengl version? */
2015
2016 attribs[index] = 99;
2017 attribs[index + 1] = 0x1000;
2018
2019 if (RGFW_majorVersion >= 4 || RGFW_majorVersion >= 3) {
2020 attribs[index + 1] = (u32) ((RGFW_majorVersion >= 4) ? 0x4100 : 0x3200);
2021 }
2022#endif
2023
2024 RGFW_GL_ADD_ATTRIB(0, 0);
2025
2026 return attribs;
2027 }
2028
2029/* EGL only (no OSMesa nor normal OPENGL) */
2030#elif defined(RGFW_EGL)
2031
2032#include <EGL/egl.h>
2033
2034#if defined(RGFW_LINK_EGL)
2035 typedef EGLBoolean(EGLAPIENTRY* PFN_eglInitialize)(EGLDisplay, EGLint*, EGLint*);
2036
2037 PFNEGLINITIALIZEPROC eglInitializeSource;
2038 PFNEGLGETCONFIGSPROC eglGetConfigsSource;
2039 PFNEGLCHOOSECONFIGPROC eglChooseConfigSource;
2040 PFNEGLCREATEWINDOWSURFACEPROC eglCreateWindowSurfaceSource;
2041 PFNEGLCREATECONTEXTPROC eglCreateContextSource;
2042 PFNEGLMAKECURRENTPROC eglMakeCurrentSource;
2043 PFNEGLGETDISPLAYPROC eglGetDisplaySource;
2044 PFNEGLSWAPBUFFERSPROC eglSwapBuffersSource;
2045 PFNEGLSWAPINTERVALPROC eglSwapIntervalSource;
2046 PFNEGLBINDAPIPROC eglBindAPISource;
2047 PFNEGLDESTROYCONTEXTPROC eglDestroyContextSource;
2048 PFNEGLTERMINATEPROC eglTerminateSource;
2049 PFNEGLDESTROYSURFACEPROC eglDestroySurfaceSource;
2050
2051#define eglInitialize eglInitializeSource
2052#define eglGetConfigs eglGetConfigsSource
2053#define eglChooseConfig eglChooseConfigSource
2054#define eglCreateWindowSurface eglCreateWindowSurfaceSource
2055#define eglCreateContext eglCreateContextSource
2056#define eglMakeCurrent eglMakeCurrentSource
2057#define eglGetDisplay eglGetDisplaySource
2058#define eglSwapBuffers eglSwapBuffersSource
2059#define eglSwapInterval eglSwapIntervalSource
2060#define eglBindAPI eglBindAPISource
2061#define eglDestroyContext eglDestroyContextSource
2062#define eglTerminate eglTerminateSource
2063#define eglDestroySurface eglDestroySurfaceSource;
2064#endif
2065
2066
2067#define EGL_SURFACE_MAJOR_VERSION_KHR 0x3098
2068#define EGL_SURFACE_MINOR_VERSION_KHR 0x30fb
2069
2070#ifndef RGFW_GL_ADD_ATTRIB
2071#define RGFW_GL_ADD_ATTRIB(attrib, attVal) \
2072 if (attVal) { \
2073 attribs[index] = attrib;\
2074 attribs[index + 1] = attVal;\
2075 index += 2;\
2076 }
2077#endif
2078
2079
2080 void RGFW_createOpenGLContext(RGFW_window* win) {
2081#if defined(RGFW_LINK_EGL)
2082 eglInitializeSource = (PFNEGLINITIALIZEPROC) eglGetProcAddress("eglInitialize");
2083 eglGetConfigsSource = (PFNEGLGETCONFIGSPROC) eglGetProcAddress("eglGetConfigs");
2084 eglChooseConfigSource = (PFNEGLCHOOSECONFIGPROC) eglGetProcAddress("eglChooseConfig");
2085 eglCreateWindowSurfaceSource = (PFNEGLCREATEWINDOWSURFACEPROC) eglGetProcAddress("eglCreateWindowSurface");
2086 eglCreateContextSource = (PFNEGLCREATECONTEXTPROC) eglGetProcAddress("eglCreateContext");
2087 eglMakeCurrentSource = (PFNEGLMAKECURRENTPROC) eglGetProcAddress("eglMakeCurrent");
2088 eglGetDisplaySource = (PFNEGLGETDISPLAYPROC) eglGetProcAddress("eglGetDisplay");
2089 eglSwapBuffersSource = (PFNEGLSWAPBUFFERSPROC) eglGetProcAddress("eglSwapBuffers");
2090 eglSwapIntervalSource = (PFNEGLSWAPINTERVALPROC) eglGetProcAddress("eglSwapInterval");
2091 eglBindAPISource = (PFNEGLBINDAPIPROC) eglGetProcAddress("eglBindAPI");
2092 eglDestroyContextSource = (PFNEGLDESTROYCONTEXTPROC) eglGetProcAddress("eglDestroyContext");
2093 eglTerminateSource = (PFNEGLTERMINATEPROC) eglGetProcAddress("eglTerminate");
2094 eglDestroySurfaceSource = (PFNEGLDESTROYSURFACEPROC) eglGetProcAddress("eglDestroySurface");
2095#endif /* RGFW_LINK_EGL */
2096
2097 #ifdef RGFW_WINDOWS
2098 win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.hdc);
2099 #elif defined(RGFW_MACOS)
2100 win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType)0);
2101 #else
2102 win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.display);
2103 #endif
2104
2105 EGLint major, minor;
2106
2107 eglInitialize(win->src.EGL_display, &major, &minor);
2108
2109 #ifndef EGL_OPENGL_ES1_BIT
2110 #define EGL_OPENGL_ES1_BIT 0x1
2111 #endif
2112
2113 EGLint egl_config[] = {
2114 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
2115 EGL_RENDERABLE_TYPE,
2116 #ifdef RGFW_OPENGL_ES1
2117 EGL_OPENGL_ES1_BIT,
2118 #elif defined(RGFW_OPENGL_ES3)
2119 EGL_OPENGL_ES3_BIT,
2120 #elif defined(RGFW_OPENGL_ES2)
2121 EGL_OPENGL_ES2_BIT,
2122 #else
2123 EGL_OPENGL_BIT,
2124 #endif
2125 EGL_NONE, EGL_NONE
2126 };
2127
2128 EGLConfig config;
2129 EGLint numConfigs;
2130 eglChooseConfig(win->src.EGL_display, egl_config, &config, 1, &numConfigs);
2131
2132 #if defined(RGFW_MACOS)
2133 void* layer = RGFW_cocoaGetLayer();
2134
2135 RGFW_window_cocoaSetLayer(win, layer);
2136
2137 win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) layer, NULL);
2138 #else
2139 win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL);
2140 #endif
2141
2142 EGLint attribs[] = {
2143 EGL_CONTEXT_CLIENT_VERSION,
2144 #ifdef RGFW_OPENGL_ES1
2145 1,
2146 #else
2147 2,
2148 #endif
2149 EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE
2150 };
2151
2152 size_t index = 4;
2153 RGFW_GL_ADD_ATTRIB(EGL_STENCIL_SIZE, RGFW_STENCIL);
2154 RGFW_GL_ADD_ATTRIB(EGL_SAMPLES, RGFW_SAMPLES);
2155
2156 if (RGFW_DOUBLE_BUFFER)
2157 RGFW_GL_ADD_ATTRIB(EGL_RENDER_BUFFER, EGL_BACK_BUFFER);
2158
2159 if (RGFW_majorVersion) {
2160 attribs[1] = RGFW_majorVersion;
2161
2162 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MAJOR_VERSION, RGFW_majorVersion);
2163 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MINOR_VERSION, RGFW_minorVersion);
2164
2165 if (RGFW_profile == RGFW_GL_CORE) {
2166 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT);
2167 }
2168 else {
2169 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT);
2170 }
2171
2172 }
2173
2174 #if defined(RGFW_OPENGL_ES1) || defined(RGFW_OPENGL_ES2) || defined(RGFW_OPENGL_ES3)
2175 eglBindAPI(EGL_OPENGL_ES_API);
2176 #else
2177 eglBindAPI(EGL_OPENGL_API);
2178 #endif
2179
2180 win->src.EGL_context = eglCreateContext(win->src.EGL_display, config, EGL_NO_CONTEXT, attribs);
2181
2182 if (win->src.EGL_context == NULL)
2183 fprintf(stderr, "failed to create an EGL opengl context\n");
2184
2185 eglMakeCurrent(win->src.EGL_display, win->src.EGL_surface, win->src.EGL_surface, win->src.EGL_context);
2186 eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface);
2187 }
2188
2189 void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
2190 eglMakeCurrent(win->src.EGL_display, win->src.EGL_surface, win->src.EGL_surface, win->src.EGL_context);
2191 }
2192
2193 #ifdef RGFW_APPLE
2194 void* RGFWnsglFramework = NULL;
2195 #elif defined(RGFW_WINDOWS)
2196 static HMODULE wglinstance = NULL;
2197 #endif
2198
2199 void* RGFW_getProcAddress(const char* procname) {
2200 #if defined(RGFW_WINDOWS)
2201 void* proc = (void*) GetProcAddress(wglinstance, procname);
2202
2203 if (proc)
2204 return proc;
2205 #endif
2206
2207 return (void*) eglGetProcAddress(procname);
2208 }
2209
2210 void RGFW_closeEGL(RGFW_window* win) {
2211 eglDestroySurface(win->src.EGL_display, win->src.EGL_surface);
2212 eglDestroyContext(win->src.EGL_display, win->src.EGL_context);
2213
2214 eglTerminate(win->src.EGL_display);
2215 }
2216
2217 void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) {
2218 assert(win != NULL);
2219
2220 eglSwapInterval(win->src.EGL_display, swapInterval);
2221
2222 }
2223#endif /* RGFW_EGL */
2224
2225/*
2226 end of RGFW_EGL defines
2227*/
2228
2229/* OPENGL Normal / EGL defines only (no OS MESA) Ends here */
2230
2231#elif defined(RGFW_OSMESA) /* OSmesa only */
2232RGFWDEF void RGFW_OSMesa_reorganize(void);
2233
2234/* reorganize buffer for osmesa */
2235void RGFW_OSMesa_reorganize(void) {
2236 u8* row = (u8*) RGFW_MALLOC(win->r.w * 3);
2237
2238 i32 half_height = win->r.h / 2;
2239 i32 stride = win->r.w * 3;
2240
2241 i32 y;
2242 for (y = 0; y < half_height; ++y) {
2243 i32 top_offset = y * stride;
2244 i32 bottom_offset = (win->r.h - y - 1) * stride;
2245 memcpy(row, win->buffer + top_offset, stride);
2246 memcpy(win->buffer + top_offset, win->buffer + bottom_offset, stride);
2247 memcpy(win->buffer + bottom_offset, row, stride);
2248 }
2249
2250 RGFW_FREE(row);
2251}
2252#endif /* RGFW_OSMesa */
2253
2254#endif /* RGFW_GL (OpenGL, EGL, OSMesa )*/
2255
2256/*
2257This is where OS specific stuff starts
2258*/
2259
2260
2261#if defined(RGFW_WAYLAND) || defined(RGFW_X11)
2262 int RGFW_eventWait_forceStop[] = {0, 0, 0}; /* for wait events */
2263
2264 #ifdef __linux__
2265 #include <linux/joystick.h>
2266 #include <fcntl.h>
2267 #include <unistd.h>
2268
2269 RGFW_Event* RGFW_linux_updateJoystick(RGFW_window* win) {
2270 static int xAxis = 0, yAxis = 0;
2271 u8 i;
2272 for (i = 0; i < RGFW_joystickCount; i++) {
2273 struct js_event e;
2274
2275
2276 if (RGFW_joysticks[i] == 0)
2277 continue;
2278
2279 i32 flags = fcntl(RGFW_joysticks[i], F_GETFL, 0);
2280 fcntl(RGFW_joysticks[i], F_SETFL, flags | O_NONBLOCK);
2281
2282 ssize_t bytes;
2283 while ((bytes = read(RGFW_joysticks[i], &e, sizeof(e))) > 0) {
2284 switch (e.type) {
2285 case JS_EVENT_BUTTON:
2286 win->event.type = e.value ? RGFW_jsButtonPressed : RGFW_jsButtonReleased;
2287 win->event.button = e.number;
2288 RGFW_jsPressed[i][e.number] = e.value;
2289 RGFW_jsButtonCallback(win, i, e.number, e.value);
2290 return &win->event;
2291 case JS_EVENT_AXIS:
2292 ioctl(RGFW_joysticks[i], JSIOCGAXES, &win->event.axisesCount);
2293
2294 if ((e.number == 0 || e.number % 2) && e.number != 1)
2295 xAxis = e.value;
2296 else
2297 yAxis = e.value;
2298
2299 win->event.axis[e.number / 2].x = xAxis;
2300 win->event.axis[e.number / 2].y = yAxis;
2301 win->event.type = RGFW_jsAxisMove;
2302 win->event.joystick = i;
2303 RGFW_jsAxisCallback(win, i, win->event.axis, win->event.axisesCount);
2304 return &win->event;
2305
2306 default: break;
2307 }
2308 }
2309 }
2310
2311 return NULL;
2312 }
2313
2314 #endif
2315#endif
2316
2317/*
2318
2319
2320Start of Linux / Unix defines
2321
2322
2323*/
2324
2325#ifdef RGFW_X11
2326#ifndef RGFW_NO_X11_CURSOR
2327#include <X11/Xcursor/Xcursor.h>
2328#endif
2329#include <dlfcn.h>
2330
2331#ifndef RGFW_NO_DPI
2332#include <X11/extensions/Xrandr.h>
2333#include <X11/Xresource.h>
2334#endif
2335
2336#include <X11/Xutil.h>
2337#include <X11/Xatom.h>
2338#include <X11/keysymdef.h>
2339#include <unistd.h>
2340
2341#include <X11/XKBlib.h> /* for converting keycode to string */
2342#include <X11/cursorfont.h> /* for hiding */
2343#include <X11/extensions/shapeconst.h>
2344#include <X11/extensions/shape.h>
2345#include <X11/extensions/XInput2.h>
2346
2347#include <limits.h> /* for data limits (mainly used in drag and drop functions) */
2348#include <poll.h>
2349
2350
2351#ifdef __linux__
2352#include <linux/joystick.h>
2353#endif
2354
2355 u8 RGFW_mouseIconSrc[] = { XC_arrow, XC_left_ptr, XC_xterm, XC_crosshair, XC_hand2, XC_sb_h_double_arrow, XC_sb_v_double_arrow, XC_bottom_left_corner, XC_bottom_right_corner, XC_fleur, XC_X_cursor};
2356 /*atoms needed for drag and drop*/
2357 Atom XdndAware, XdndTypeList, XdndSelection, XdndEnter, XdndPosition, XdndStatus, XdndLeave, XdndDrop, XdndFinished, XdndActionCopy, XtextPlain, XtextUriList;
2358
2359 Atom wm_delete_window = 0;
2360
2361#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)
2362 typedef XcursorImage* (*PFN_XcursorImageCreate)(int, int);
2363 typedef void (*PFN_XcursorImageDestroy)(XcursorImage*);
2364 typedef Cursor(*PFN_XcursorImageLoadCursor)(Display*, const XcursorImage*);
2365#endif
2366#ifdef RGFW_OPENGL
2367 typedef GLXContext(*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
2368#endif
2369
2370#if !defined(RGFW_NO_X11_XI_PRELOAD)
2371 typedef int (* PFN_XISelectEvents)(Display*,Window,XIEventMask*,int);
2372 PFN_XISelectEvents XISelectEventsSrc = NULL;
2373 #define XISelectEvents XISelectEventsSrc
2374
2375 void* X11Xihandle = NULL;
2376#endif
2377
2378#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)
2379 PFN_XcursorImageLoadCursor XcursorImageLoadCursorSrc = NULL;
2380 PFN_XcursorImageCreate XcursorImageCreateSrc = NULL;
2381 PFN_XcursorImageDestroy XcursorImageDestroySrc = NULL;
2382
2383#define XcursorImageLoadCursor XcursorImageLoadCursorSrc
2384#define XcursorImageCreate XcursorImageCreateSrc
2385#define XcursorImageDestroy XcursorImageDestroySrc
2386
2387 void* X11Cursorhandle = NULL;
2388#endif
2389
2390 u32 RGFW_windowsOpen = 0;
2391
2392#ifdef RGFW_OPENGL
2393 void* RGFW_getProcAddress(const char* procname) { return (void*) glXGetProcAddress((GLubyte*) procname); }
2394#endif
2395
2396 RGFWDEF void RGFW_init_buffer(RGFW_window* win, XVisualInfo* vi);
2397 void RGFW_init_buffer(RGFW_window* win, XVisualInfo* vi) {
2398#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
2399 if (RGFW_bufferSize.w == 0 && RGFW_bufferSize.h == 0)
2400 RGFW_bufferSize = RGFW_getScreenSize();
2401
2402 win->buffer = (u8*)RGFW_MALLOC(RGFW_bufferSize.w * RGFW_bufferSize.h * 4);
2403
2404 #ifdef RGFW_OSMESA
2405 win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL);
2406 OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, win->r.w, win->r.h);
2407 #endif
2408
2409 win->src.bitmap = XCreateImage(
2410 win->src.display, XDefaultVisual(win->src.display, vi->screen),
2411 vi->depth,
2412 ZPixmap, 0, NULL, RGFW_bufferSize.w, RGFW_bufferSize.h,
2413 32, 0
2414 );
2415
2416 win->src.gc = XCreateGC(win->src.display, win->src.window, 0, NULL);
2417
2418 #else
2419 RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
2420 RGFW_UNUSED(vi)
2421 #endif
2422 }
2423
2424
2425
2426 void RGFW_window_setBorder(RGFW_window* win, u8 border) {
2427 static Atom _MOTIF_WM_HINTS = 0;
2428 if (_MOTIF_WM_HINTS == 0 )
2429 _MOTIF_WM_HINTS = XInternAtom(win->src.display, "_MOTIF_WM_HINTS", False);
2430
2431 struct __x11WindowHints {
2432 unsigned long flags, functions, decorations, status;
2433 long input_mode;
2434 } hints;
2435 hints.flags = (1L << 1);
2436 hints.decorations = border;
2437
2438 XChangeProperty(
2439 win->src.display, win->src.window,
2440 _MOTIF_WM_HINTS, _MOTIF_WM_HINTS,
2441 32, PropModeReplace, (u8*)&hints, 5
2442 );
2443 }
2444
2445 void RGFW_releaseCursor(RGFW_window* win) {
2446 XUngrabPointer(win->src.display, CurrentTime);
2447
2448 /* disable raw input */
2449 unsigned char mask[] = { 0 };
2450 XIEventMask em;
2451 em.deviceid = XIAllMasterDevices;
2452 em.mask_len = sizeof(mask);
2453 em.mask = mask;
2454
2455 XISelectEvents(win->src.display, XDefaultRootWindow(win->src.display), &em, 1);
2456 }
2457
2458 void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) {
2459 /* enable raw input */
2460 unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 };
2461 XISetMask(mask, XI_RawMotion);
2462
2463 XIEventMask em;
2464 em.deviceid = XIAllMasterDevices;
2465 em.mask_len = sizeof(mask);
2466 em.mask = mask;
2467
2468 XISelectEvents(win->src.display, XDefaultRootWindow(win->src.display), &em, 1);
2469
2470 XGrabPointer(win->src.display, win->src.window, True, PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
2471
2472 RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (i32)(r.w / 2), win->r.y + (i32)(r.h / 2)));
2473 }
2474
2475 RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) {
2476#if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD)
2477 if (X11Cursorhandle == NULL) {
2478#if defined(__CYGWIN__)
2479 X11Cursorhandle = dlopen("libXcursor-1.so", RTLD_LAZY | RTLD_LOCAL);
2480#elif defined(__OpenBSD__) || defined(__NetBSD__)
2481 X11Cursorhandle = dlopen("libXcursor.so", RTLD_LAZY | RTLD_LOCAL);
2482#else
2483 X11Cursorhandle = dlopen("libXcursor.so.1", RTLD_LAZY | RTLD_LOCAL);
2484#endif
2485
2486 XcursorImageCreateSrc = (PFN_XcursorImageCreate) dlsym(X11Cursorhandle, "XcursorImageCreate");
2487 XcursorImageDestroySrc = (PFN_XcursorImageDestroy) dlsym(X11Cursorhandle, "XcursorImageDestroy");
2488 XcursorImageLoadCursorSrc = (PFN_XcursorImageLoadCursor) dlsym(X11Cursorhandle, "XcursorImageLoadCursor");
2489 }
2490#endif
2491
2492#if !defined(RGFW_NO_X11_XI_PRELOAD)
2493 if (X11Xihandle == NULL) {
2494#if defined(__CYGWIN__)
2495 X11Xihandle = dlopen("libXi-6.so", RTLD_LAZY | RTLD_LOCAL);
2496#elif defined(__OpenBSD__) || defined(__NetBSD__)
2497 X11Xihandle = dlopen("libXi.so", RTLD_LAZY | RTLD_LOCAL);
2498#else
2499 X11Xihandle = dlopen("libXi.so.6", RTLD_LAZY | RTLD_LOCAL);
2500#endif
2501
2502 XISelectEventsSrc = (PFN_XISelectEvents) dlsym(X11Xihandle, "XISelectEvents");
2503 }
2504#endif
2505
2506 XInitThreads(); /*!< init X11 threading*/
2507
2508 if (args & RGFW_OPENGL_SOFTWARE)
2509 setenv("LIBGL_ALWAYS_SOFTWARE", "1", 1);
2510
2511 RGFW_window* win = RGFW_window_basic_init(rect, args);
2512
2513 u64 event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | FocusChangeMask | LeaveWindowMask | EnterWindowMask | ExposureMask; /*!< X11 events accepted*/
2514
2515#ifdef RGFW_OPENGL
2516 u32* visual_attribs = RGFW_initFormatAttribs(args & RGFW_OPENGL_SOFTWARE);
2517 i32 fbcount;
2518 GLXFBConfig* fbc = glXChooseFBConfig((Display*) win->src.display, DefaultScreen(win->src.display), (i32*) visual_attribs, &fbcount);
2519
2520 i32 best_fbc = -1;
2521
2522 if (fbcount == 0) {
2523 printf("Failed to find any valid GLX visual configs\n");
2524 return NULL;
2525 }
2526
2527 u32 i;
2528 for (i = 0; i < (u32)fbcount; i++) {
2529 XVisualInfo* vi = glXGetVisualFromFBConfig((Display*) win->src.display, fbc[i]);
2530 if (vi == NULL)
2531 continue;
2532
2533 XFree(vi);
2534
2535 i32 samp_buf, samples;
2536 glXGetFBConfigAttrib((Display*) win->src.display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
2537 glXGetFBConfigAttrib((Display*) win->src.display, fbc[i], GLX_SAMPLES, &samples);
2538
2539 if ((!(args & RGFW_TRANSPARENT_WINDOW) || vi->depth == 32) &&
2540 (best_fbc < 0 || samp_buf) && (samples == RGFW_SAMPLES || best_fbc == -1)) {
2541 best_fbc = i;
2542 }
2543 }
2544
2545 if (best_fbc == -1) {
2546 printf("Failed to get a valid GLX visual\n");
2547 return NULL;
2548 }
2549
2550 GLXFBConfig bestFbc = fbc[best_fbc];
2551
2552 /* Get a visual */
2553 XVisualInfo* vi = glXGetVisualFromFBConfig((Display*) win->src.display, bestFbc);
2554
2555 XFree(fbc);
2556#else
2557 XVisualInfo viNorm;
2558
2559 viNorm.visual = DefaultVisual((Display*) win->src.display, DefaultScreen((Display*) win->src.display));
2560
2561 viNorm.depth = 0;
2562 XVisualInfo* vi = &viNorm;
2563
2564 XMatchVisualInfo((Display*) win->src.display, DefaultScreen((Display*) win->src.display), 32, TrueColor, vi); /*!< for RGBA backgrounds*/
2565#endif
2566 /* make X window attrubutes*/
2567 XSetWindowAttributes swa;
2568 Colormap cmap;
2569
2570 swa.colormap = cmap = XCreateColormap((Display*) win->src.display,
2571 DefaultRootWindow(win->src.display),
2572 vi->visual, AllocNone);
2573
2574 swa.background_pixmap = None;
2575 swa.border_pixel = 0;
2576 swa.event_mask = event_mask;
2577
2578 swa.background_pixel = 0;
2579
2580 /* create the window*/
2581 win->src.window = XCreateWindow((Display*) win->src.display, DefaultRootWindow((Display*) win->src.display), win->r.x, win->r.y, win->r.w, win->r.h,
2582 0, vi->depth, InputOutput, vi->visual,
2583 CWColormap | CWBorderPixel | CWBackPixel | CWEventMask, &swa);
2584
2585 XFreeColors((Display*) win->src.display, cmap, NULL, 0, 0);
2586
2587 #ifdef RGFW_OPENGL
2588 XFree(vi);
2589 #endif
2590
2591 // In your .desktop app, if you set the property
2592 // StartupWMClass=RGFW that will assoicate the launcher icon
2593 // with your application - robrohan
2594
2595 if (RGFW_className == NULL)
2596 RGFW_className = (char*)name;
2597
2598 XClassHint *hint = XAllocClassHint();
2599 assert(hint != NULL);
2600 hint->res_class = (char*)RGFW_className;
2601 hint->res_name = (char*)name; // just use the window name as the app name
2602 XSetClassHint((Display*) win->src.display, win->src.window, hint);
2603 XFree(hint);
2604
2605 if ((args & RGFW_NO_INIT_API) == 0) {
2606#ifdef RGFW_OPENGL /* This is the second part of setting up opengl. This is where we ask OpenGL for a specific version. */
2607 i32 context_attribs[7] = { 0, 0, 0, 0, 0, 0, 0 };
2608 context_attribs[0] = GLX_CONTEXT_PROFILE_MASK_ARB;
2609 if (RGFW_profile == RGFW_GL_CORE)
2610 context_attribs[1] = GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
2611 else
2612 context_attribs[1] = GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
2613
2614 if (RGFW_majorVersion || RGFW_minorVersion) {
2615 context_attribs[2] = GLX_CONTEXT_MAJOR_VERSION_ARB;
2616 context_attribs[3] = RGFW_majorVersion;
2617 context_attribs[4] = GLX_CONTEXT_MINOR_VERSION_ARB;
2618 context_attribs[5] = RGFW_minorVersion;
2619 }
2620
2621 glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
2622 glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)
2623 glXGetProcAddressARB((GLubyte*) "glXCreateContextAttribsARB");
2624
2625 GLXContext ctx = NULL;
2626
2627 if (RGFW_root != NULL)
2628 ctx = RGFW_root->src.ctx;
2629
2630 win->src.ctx = glXCreateContextAttribsARB((Display*) win->src.display, bestFbc, ctx, True, context_attribs);
2631#endif
2632 if (RGFW_root == NULL)
2633 RGFW_root = win;
2634
2635 RGFW_init_buffer(win, vi);
2636 }
2637
2638
2639 #ifndef RGFW_NO_MONITOR
2640 if (args & RGFW_SCALE_TO_MONITOR)
2641 RGFW_window_scaleToMonitor(win);
2642 #endif
2643
2644 if (args & RGFW_CENTER) {
2645 RGFW_area screenR = RGFW_getScreenSize();
2646 RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2));
2647 }
2648
2649 if (args & RGFW_NO_RESIZE) { /* make it so the user can't resize the window*/
2650 XSizeHints* sh = XAllocSizeHints();
2651 sh->flags = (1L << 4) | (1L << 5);
2652 sh->min_width = sh->max_width = win->r.w;
2653 sh->min_height = sh->max_height = win->r.h;
2654
2655 XSetWMSizeHints((Display*) win->src.display, (Drawable) win->src.window, sh, XA_WM_NORMAL_HINTS);
2656 XFree(sh);
2657 }
2658
2659 if (args & RGFW_NO_BORDER) {
2660 RGFW_window_setBorder(win, 0);
2661 }
2662
2663 XSelectInput((Display*) win->src.display, (Drawable) win->src.window, event_mask); /*!< tell X11 what events we want*/
2664
2665 /* make it so the user can't close the window until the program does*/
2666 if (wm_delete_window == 0)
2667 wm_delete_window = XInternAtom((Display*) win->src.display, "WM_DELETE_WINDOW", False);
2668
2669 XSetWMProtocols((Display*) win->src.display, (Drawable) win->src.window, &wm_delete_window, 1);
2670
2671 /* connect the context to the window*/
2672#ifdef RGFW_OPENGL
2673 if ((args & RGFW_NO_INIT_API) == 0)
2674 glXMakeCurrent((Display*) win->src.display, (Drawable) win->src.window, (GLXContext) win->src.ctx);
2675#endif
2676
2677 /* set the background*/
2678 XStoreName((Display*) win->src.display, (Drawable) win->src.window, name); /*!< set the name*/
2679
2680 XMapWindow((Display*) win->src.display, (Drawable) win->src.window); /* draw the window*/
2681 XMoveWindow((Display*) win->src.display, (Drawable) win->src.window, win->r.x, win->r.y); /*!< move the window to it's proper cords*/
2682
2683 if (args & RGFW_ALLOW_DND) { /* init drag and drop atoms and turn on drag and drop for this window */
2684 win->_winArgs |= RGFW_ALLOW_DND;
2685
2686 XdndTypeList = XInternAtom((Display*) win->src.display, "XdndTypeList", False);
2687 XdndSelection = XInternAtom((Display*) win->src.display, "XdndSelection", False);
2688
2689 /* client messages */
2690 XdndEnter = XInternAtom((Display*) win->src.display, "XdndEnter", False);
2691 XdndPosition = XInternAtom((Display*) win->src.display, "XdndPosition", False);
2692 XdndStatus = XInternAtom((Display*) win->src.display, "XdndStatus", False);
2693 XdndLeave = XInternAtom((Display*) win->src.display, "XdndLeave", False);
2694 XdndDrop = XInternAtom((Display*) win->src.display, "XdndDrop", False);
2695 XdndFinished = XInternAtom((Display*) win->src.display, "XdndFinished", False);
2696
2697 /* actions */
2698 XdndActionCopy = XInternAtom((Display*) win->src.display, "XdndActionCopy", False);
2699
2700 XtextUriList = XInternAtom((Display*) win->src.display, "text/uri-list", False);
2701 XtextPlain = XInternAtom((Display*) win->src.display, "text/plain", False);
2702
2703 XdndAware = XInternAtom((Display*) win->src.display, "XdndAware", False);
2704 const u8 version = 5;
2705
2706 XChangeProperty((Display*) win->src.display, (Window) win->src.window,
2707 XdndAware, 4, 32,
2708 PropModeReplace, &version, 1); /*!< turns on drag and drop */
2709 }
2710
2711 #ifdef RGFW_EGL
2712 if ((args & RGFW_NO_INIT_API) == 0)
2713 RGFW_createOpenGLContext(win);
2714 #endif
2715
2716 RGFW_window_setMouseDefault(win);
2717
2718 RGFW_windowsOpen++;
2719
2720 return win; /*return newly created window*/
2721 }
2722
2723 RGFW_area RGFW_getScreenSize(void) {
2724 assert(RGFW_root != NULL);
2725
2726 Screen* scrn = DefaultScreenOfDisplay((Display*) RGFW_root->src.display);
2727 return RGFW_AREA(scrn->width, scrn->height);
2728 }
2729
2730 RGFW_point RGFW_getGlobalMousePoint(void) {
2731 assert(RGFW_root != NULL);
2732
2733 RGFW_point RGFWMouse;
2734
2735 i32 x, y;
2736 u32 z;
2737 Window window1, window2;
2738 XQueryPointer((Display*) RGFW_root->src.display, XDefaultRootWindow((Display*) RGFW_root->src.display), &window1, &window2, &RGFWMouse.x, &RGFWMouse.y, &x, &y, &z);
2739
2740 return RGFWMouse;
2741 }
2742
2743 RGFW_point RGFW_window_getMousePoint(RGFW_window* win) {
2744 assert(win != NULL);
2745
2746 RGFW_point RGFWMouse;
2747
2748 i32 x, y;
2749 u32 z;
2750 Window window1, window2;
2751 XQueryPointer((Display*) win->src.display, win->src.window, &window1, &window2, &x, &y, &RGFWMouse.x, &RGFWMouse.y, &z);
2752
2753 return RGFWMouse;
2754 }
2755
2756 int xAxis = 0, yAxis = 0;
2757
2758 RGFW_Event* RGFW_window_checkEvent(RGFW_window* win) {
2759 assert(win != NULL);
2760
2761 static struct {
2762 long source, version;
2763 i32 format;
2764 } xdnd;
2765
2766 if (win->event.type == 0)
2767 RGFW_resetKey();
2768
2769 if (win->event.type == RGFW_quit) {
2770 return NULL;
2771 }
2772
2773 win->event.type = 0;
2774
2775#ifdef __linux__
2776 RGFW_Event* event = RGFW_linux_updateJoystick(win);
2777 if (event != NULL)
2778 return event;
2779#endif
2780
2781 XPending(win->src.display);
2782
2783 XEvent E; /*!< raw X11 event */
2784
2785 /* if there is no unread qued events, get a new one */
2786 if ((QLength(win->src.display) || XEventsQueued((Display*) win->src.display, QueuedAlready) + XEventsQueued((Display*) win->src.display, QueuedAfterReading))
2787 && win->event.type != RGFW_quit
2788 )
2789 XNextEvent((Display*) win->src.display, &E);
2790 else {
2791 return NULL;
2792 }
2793
2794 u32 i;
2795 win->event.type = 0;
2796
2797
2798 switch (E.type) {
2799 case KeyPress:
2800 case KeyRelease: {
2801 win->event.repeat = RGFW_FALSE;
2802 /* check if it's a real key release */
2803 if (E.type == KeyRelease && XEventsQueued((Display*) win->src.display, QueuedAfterReading)) { /* get next event if there is one*/
2804 XEvent NE;
2805 XPeekEvent((Display*) win->src.display, &NE);
2806
2807 if (E.xkey.time == NE.xkey.time && E.xkey.keycode == NE.xkey.keycode) /* check if the current and next are both the same*/
2808 win->event.repeat = RGFW_TRUE;
2809 }
2810
2811 /* set event key data */
2812 KeySym sym = (KeySym)XkbKeycodeToKeysym((Display*) win->src.display, E.xkey.keycode, 0, E.xkey.state & ShiftMask ? 1 : 0);
2813 win->event.keyCode = RGFW_apiKeyCodeToRGFW(E.xkey.keycode);
2814
2815 char* str = (char*)XKeysymToString(sym);
2816 if (str != NULL)
2817 strncpy(win->event.keyName, str, 16);
2818
2819 win->event.keyName[15] = '\0';
2820
2821 RGFW_keyboard[win->event.keyCode].prev = RGFW_isPressed(win, win->event.keyCode);
2822
2823 /* get keystate data */
2824 win->event.type = (E.type == KeyPress) ? RGFW_keyPressed : RGFW_keyReleased;
2825
2826 XKeyboardState keystate;
2827 XGetKeyboardControl((Display*) win->src.display, &keystate);
2828
2829 RGFW_updateLockState(win, (keystate.led_mask & 1), (keystate.led_mask & 2));
2830 RGFW_keyboard[win->event.keyCode].current = (E.type == KeyPress);
2831 RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, (E.type == KeyPress));
2832 break;
2833 }
2834 case ButtonPress:
2835 case ButtonRelease:
2836 win->event.type = RGFW_mouseButtonPressed + (E.type == ButtonRelease); // the events match
2837
2838 switch(win->event.button) {
2839 case RGFW_mouseScrollUp:
2840 win->event.scroll = 1;
2841 break;
2842 case RGFW_mouseScrollDown:
2843 win->event.scroll = -1;
2844 break;
2845 default: break;
2846 }
2847
2848 win->event.button = E.xbutton.button;
2849 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
2850
2851 if (win->event.repeat == RGFW_FALSE)
2852 win->event.repeat = RGFW_isPressed(win, win->event.keyCode);
2853
2854 RGFW_mouseButtons[win->event.button].current = (E.type == ButtonPress);
2855 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, (E.type == ButtonPress));
2856 break;
2857
2858 case MotionNotify:
2859 win->event.point.x = E.xmotion.x;
2860 win->event.point.y = E.xmotion.y;
2861
2862 if ((win->_winArgs & RGFW_HOLD_MOUSE)) {
2863 win->event.point.y = E.xmotion.y;
2864
2865 win->event.point.x = win->_lastMousePoint.x - abs(win->event.point.x);
2866 win->event.point.y = win->_lastMousePoint.y - abs(win->event.point.y);
2867 }
2868
2869 win->_lastMousePoint = RGFW_POINT(E.xmotion.x, E.xmotion.y);
2870
2871 win->event.type = RGFW_mousePosChanged;
2872 RGFW_mousePosCallback(win, win->event.point);
2873 break;
2874
2875 case GenericEvent: {
2876 /* MotionNotify is used for mouse events if the mouse isn't held */
2877 if (!(win->_winArgs & RGFW_HOLD_MOUSE)) {
2878 XFreeEventData(win->src.display, &E.xcookie);
2879 break;
2880 }
2881
2882 XGetEventData(win->src.display, &E.xcookie);
2883 if (E.xcookie.evtype == XI_RawMotion) {
2884 XIRawEvent *raw = (XIRawEvent *)E.xcookie.data;
2885 if (raw->valuators.mask_len == 0) {
2886 XFreeEventData(win->src.display, &E.xcookie);
2887 break;
2888 }
2889
2890 double deltaX = 0.0f;
2891 double deltaY = 0.0f;
2892
2893 /* check if relative motion data exists where we think it does */
2894 if (XIMaskIsSet(raw->valuators.mask, 0) != 0)
2895 deltaX += raw->raw_values[0];
2896 if (XIMaskIsSet(raw->valuators.mask, 1) != 0)
2897 deltaY += raw->raw_values[1];
2898
2899 win->event.point = RGFW_POINT((i32)deltaX, (i32)deltaY);
2900
2901 RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2)));
2902
2903 win->event.type = RGFW_mousePosChanged;
2904 RGFW_mousePosCallback(win, win->event.point);
2905 }
2906
2907 XFreeEventData(win->src.display, &E.xcookie);
2908 break;
2909 }
2910
2911 case Expose:
2912 win->event.type = RGFW_windowRefresh;
2913 RGFW_windowRefreshCallback(win);
2914 break;
2915
2916 case ClientMessage:
2917 /* if the client closed the window*/
2918 if (E.xclient.data.l[0] == (i64) wm_delete_window) {
2919 win->event.type = RGFW_quit;
2920 RGFW_windowQuitCallback(win);
2921 break;
2922 }
2923
2924 /* reset DND values */
2925 if (win->event.droppedFilesCount) {
2926 for (i = 0; i < win->event.droppedFilesCount; i++)
2927 win->event.droppedFiles[i][0] = '\0';
2928 }
2929
2930 win->event.droppedFilesCount = 0;
2931
2932 if ((win->_winArgs & RGFW_ALLOW_DND) == 0)
2933 break;
2934
2935 XEvent reply = { ClientMessage };
2936 reply.xclient.window = xdnd.source;
2937 reply.xclient.format = 32;
2938 reply.xclient.data.l[0] = (long) win->src.window;
2939 reply.xclient.data.l[1] = 0;
2940 reply.xclient.data.l[2] = None;
2941
2942 if (E.xclient.message_type == XdndEnter) {
2943 unsigned long count;
2944 Atom* formats;
2945 Atom real_formats[6];
2946
2947 Bool list = E.xclient.data.l[1] & 1;
2948
2949 xdnd.source = E.xclient.data.l[0];
2950 xdnd.version = E.xclient.data.l[1] >> 24;
2951 xdnd.format = None;
2952
2953 if (xdnd.version > 5)
2954 break;
2955
2956 if (list) {
2957 Atom actualType;
2958 i32 actualFormat;
2959 unsigned long bytesAfter;
2960
2961 XGetWindowProperty((Display*) win->src.display,
2962 xdnd.source,
2963 XdndTypeList,
2964 0,
2965 LONG_MAX,
2966 False,
2967 4,
2968 &actualType,
2969 &actualFormat,
2970 &count,
2971 &bytesAfter,
2972 (u8**) &formats);
2973 } else {
2974 count = 0;
2975
2976 if (E.xclient.data.l[2] != None)
2977 real_formats[count++] = E.xclient.data.l[2];
2978 if (E.xclient.data.l[3] != None)
2979 real_formats[count++] = E.xclient.data.l[3];
2980 if (E.xclient.data.l[4] != None)
2981 real_formats[count++] = E.xclient.data.l[4];
2982
2983 formats = real_formats;
2984 }
2985
2986 unsigned long i;
2987 for (i = 0; i < count; i++) {
2988 if (formats[i] == XtextUriList || formats[i] == XtextPlain) {
2989 xdnd.format = formats[i];
2990 break;
2991 }
2992 }
2993
2994 if (list) {
2995 XFree(formats);
2996 }
2997
2998 break;
2999 }
3000 if (E.xclient.message_type == XdndPosition) {
3001 const i32 xabs = (E.xclient.data.l[2] >> 16) & 0xffff;
3002 const i32 yabs = (E.xclient.data.l[2]) & 0xffff;
3003 Window dummy;
3004 i32 xpos, ypos;
3005
3006 if (xdnd.version > 5)
3007 break;
3008
3009 XTranslateCoordinates((Display*) win->src.display,
3010 XDefaultRootWindow((Display*) win->src.display),
3011 (Window) win->src.window,
3012 xabs, yabs,
3013 &xpos, &ypos,
3014 &dummy);
3015
3016 win->event.point.x = xpos;
3017 win->event.point.y = ypos;
3018
3019 reply.xclient.window = xdnd.source;
3020 reply.xclient.message_type = XdndStatus;
3021
3022 if (xdnd.format) {
3023 reply.xclient.data.l[1] = 1;
3024 if (xdnd.version >= 2)
3025 reply.xclient.data.l[4] = XdndActionCopy;
3026 }
3027
3028 XSendEvent((Display*) win->src.display, xdnd.source, False, NoEventMask, &reply);
3029 XFlush((Display*) win->src.display);
3030 break;
3031 }
3032
3033 if (E.xclient.message_type != XdndDrop)
3034 break;
3035
3036 if (xdnd.version > 5)
3037 break;
3038
3039 win->event.type = RGFW_dnd_init;
3040
3041 if (xdnd.format) {
3042 Time time = CurrentTime;
3043
3044 if (xdnd.version >= 1)
3045 time = E.xclient.data.l[2];
3046
3047 XConvertSelection((Display*) win->src.display,
3048 XdndSelection,
3049 xdnd.format,
3050 XdndSelection,
3051 (Window) win->src.window,
3052 time);
3053 } else if (xdnd.version >= 2) {
3054 XEvent reply = { ClientMessage };
3055
3056 XSendEvent((Display*) win->src.display, xdnd.source,
3057 False, NoEventMask, &reply);
3058 XFlush((Display*) win->src.display);
3059 }
3060
3061 RGFW_dndInitCallback(win, win->event.point);
3062 break;
3063 case SelectionNotify: {
3064 /* this is only for checking for xdnd drops */
3065 if (E.xselection.property != XdndSelection || !(win->_winArgs | RGFW_ALLOW_DND))
3066 break;
3067
3068 char* data;
3069 unsigned long result;
3070
3071 Atom actualType;
3072 i32 actualFormat;
3073 unsigned long bytesAfter;
3074
3075 XGetWindowProperty((Display*) win->src.display, E.xselection.requestor, E.xselection.property, 0, LONG_MAX, False, E.xselection.target, &actualType, &actualFormat, &result, &bytesAfter, (u8**) &data);
3076
3077 if (result == 0)
3078 break;
3079
3080 /*
3081 SOURCED FROM GLFW _glfwParseUriList
3082 Copyright (c) 2002-2006 Marcus Geelnard
3083 Copyright (c) 2006-2019 Camilla Löwy
3084 */
3085
3086 const char* prefix = (const char*)"file://";
3087
3088 char* line;
3089
3090 win->event.droppedFilesCount = 0;
3091
3092 win->event.type = RGFW_dnd;
3093
3094 while ((line = strtok(data, "\r\n"))) {
3095 char path[RGFW_MAX_PATH];
3096
3097 data = NULL;
3098
3099 if (line[0] == '#')
3100 continue;
3101
3102 char* l;
3103 for (l = line; 1; l++) {
3104 if ((l - line) > 7)
3105 break;
3106 else if (*l != prefix[(l - line)])
3107 break;
3108 else if (*l == '\0' && prefix[(l - line)] == '\0') {
3109 line += 7;
3110 while (*line != '/')
3111 line++;
3112 break;
3113 } else if (*l == '\0')
3114 break;
3115 }
3116
3117 win->event.droppedFilesCount++;
3118
3119 size_t index = 0;
3120 while (*line) {
3121 if (line[0] == '%' && line[1] && line[2]) {
3122 const char digits[3] = { line[1], line[2], '\0' };
3123 path[index] = (char) strtol(digits, NULL, 16);
3124 line += 2;
3125 } else
3126 path[index] = *line;
3127
3128 index++;
3129 line++;
3130 }
3131 path[index] = '\0';
3132 strncpy(win->event.droppedFiles[win->event.droppedFilesCount - 1], path, index + 1);
3133 }
3134
3135 if (data)
3136 XFree(data);
3137
3138 if (xdnd.version >= 2) {
3139 reply.xclient.message_type = XdndFinished;
3140 reply.xclient.data.l[1] = result;
3141 reply.xclient.data.l[2] = XdndActionCopy;
3142
3143 XSendEvent((Display*) win->src.display, xdnd.source, False, NoEventMask, &reply);
3144 XFlush((Display*) win->src.display);
3145 }
3146
3147 RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount);
3148 break;
3149 }
3150 case FocusIn:
3151 win->event.inFocus = 1;
3152 win->event.type = RGFW_focusIn;
3153 RGFW_focusCallback(win, 1);
3154 break;
3155
3156 break;
3157 case FocusOut:
3158 win->event.inFocus = 0;
3159 win->event.type = RGFW_focusOut;
3160 RGFW_focusCallback(win, 0);
3161 break;
3162
3163 case EnterNotify: {
3164 win->event.type = RGFW_mouseEnter;
3165 win->event.point.x = E.xcrossing.x;
3166 win->event.point.y = E.xcrossing.y;
3167 RGFW_mouseNotifyCallBack(win, win->event.point, 1);
3168 break;
3169 }
3170
3171 case LeaveNotify: {
3172 win->event.type = RGFW_mouseLeave;
3173 RGFW_mouseNotifyCallBack(win, win->event.point, 0);
3174 break;
3175 }
3176
3177 case ConfigureNotify: {
3178 /* detect resize */
3179 if (E.xconfigure.width != win->r.w || E.xconfigure.height != win->r.h) {
3180 win->event.type = RGFW_windowResized;
3181 win->r = RGFW_RECT(win->r.x, win->r.y, E.xconfigure.width, E.xconfigure.height);
3182 RGFW_windowResizeCallback(win, win->r);
3183 break;
3184 }
3185
3186 /* detect move */
3187 if (E.xconfigure.x != win->r.x || E.xconfigure.y != win->r.y) {
3188 win->event.type = RGFW_windowMoved;
3189 win->r = RGFW_RECT(E.xconfigure.x, E.xconfigure.y, win->r.w, win->r.h);
3190 RGFW_windowMoveCallback(win, win->r);
3191 break;
3192 }
3193
3194 break;
3195 }
3196 default: {
3197 break;
3198 }
3199 }
3200
3201 XFlush((Display*) win->src.display);
3202
3203 if (win->event.type)
3204 return &win->event;
3205 else
3206 return NULL;
3207 }
3208
3209 void RGFW_window_move(RGFW_window* win, RGFW_point v) {
3210 assert(win != NULL);
3211 win->r.x = v.x;
3212 win->r.y = v.y;
3213
3214 XMoveWindow((Display*) win->src.display, (Window) win->src.window, v.x, v.y);
3215 }
3216
3217
3218 void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
3219 assert(win != NULL);
3220 win->r.w = a.w;
3221 win->r.h = a.h;
3222
3223 XResizeWindow((Display*) win->src.display, (Window) win->src.window, a.w, a.h);
3224 }
3225
3226 void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) {
3227 assert(win != NULL);
3228
3229 if (a.w == 0 && a.h == 0)
3230 return;
3231
3232 XSizeHints hints;
3233 long flags;
3234
3235 XGetWMNormalHints(win->src.display, (Window) win->src.window, &hints, &flags);
3236
3237 hints.flags |= PMinSize;
3238
3239 hints.min_width = a.w;
3240 hints.min_height = a.h;
3241
3242 XSetWMNormalHints(win->src.display, (Window) win->src.window, &hints);
3243 }
3244
3245 void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) {
3246 assert(win != NULL);
3247
3248 if (a.w == 0 && a.h == 0)
3249 return;
3250
3251 XSizeHints hints;
3252 long flags;
3253
3254 XGetWMNormalHints(win->src.display, (Window) win->src.window, &hints, &flags);
3255
3256 hints.flags |= PMaxSize;
3257
3258 hints.max_width = a.w;
3259 hints.max_height = a.h;
3260
3261 XSetWMNormalHints(win->src.display, (Window) win->src.window, &hints);
3262 }
3263
3264
3265 void RGFW_window_minimize(RGFW_window* win) {
3266 assert(win != NULL);
3267
3268 XIconifyWindow(win->src.display, (Window) win->src.window, DefaultScreen(win->src.display));
3269 XFlush(win->src.display);
3270 }
3271
3272 void RGFW_window_restore(RGFW_window* win) {
3273 assert(win != NULL);
3274
3275 XMapWindow(win->src.display, (Window) win->src.window);
3276 XFlush(win->src.display);
3277 }
3278
3279 void RGFW_window_setName(RGFW_window* win, char* name) {
3280 assert(win != NULL);
3281
3282 XStoreName((Display*) win->src.display, (Window) win->src.window, name);
3283 }
3284
3285 void* RGFW_libxshape = NULL;
3286
3287 #ifndef RGFW_NO_PASSTHROUGH
3288 void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) {
3289 assert(win != NULL);
3290
3291 #if defined(__CYGWIN__)
3292 RGFW_libxshape = dlopen("libXext-6.so", RTLD_LAZY | RTLD_LOCAL);
3293 #elif defined(__OpenBSD__) || defined(__NetBSD__)
3294 RGFW_libxshape = dlopen("libXext.so", RTLD_LAZY | RTLD_LOCAL);
3295 #else
3296 RGFW_libxshape = dlopen("libXext.so.6", RTLD_LAZY | RTLD_LOCAL);
3297 #endif
3298
3299 typedef void (* PFN_XShapeCombineMask)(Display*,Window,int,int,int,Pixmap,int);
3300 static PFN_XShapeCombineMask XShapeCombineMask;
3301
3302 typedef void (* PFN_XShapeCombineRegion)(Display*,Window,int,int,int,Region,int);
3303 static PFN_XShapeCombineRegion XShapeCombineRegion;
3304
3305 if (XShapeCombineMask != NULL)
3306 XShapeCombineMask = (PFN_XShapeCombineMask) dlsym(RGFW_libxshape, "XShapeCombineMask");
3307
3308 if (XShapeCombineRegion != NULL)
3309 XShapeCombineRegion = (PFN_XShapeCombineRegion) dlsym(RGFW_libxshape, "XShapeCombineMask");
3310
3311 if (passthrough) {
3312 Region region = XCreateRegion();
3313 XShapeCombineRegion(win->src.display, win->src.window, ShapeInput, 0, 0, region, ShapeSet);
3314 XDestroyRegion(region);
3315
3316 return;
3317 }
3318
3319 XShapeCombineMask(win->src.display, win->src.window, ShapeInput, 0, 0, None, ShapeSet);
3320 }
3321 #endif
3322
3323 /*
3324 the majority function is sourced from GLFW
3325 */
3326
3327 void RGFW_window_setIcon(RGFW_window* win, u8* icon, RGFW_area a, i32 channels) {
3328 assert(win != NULL);
3329
3330 i32 longCount = 2 + a.w * a.h;
3331
3332 u64* X11Icon = (u64*) RGFW_MALLOC(longCount * sizeof(u64));
3333 u64* target = X11Icon;
3334
3335 *target++ = a.w;
3336 *target++ = a.h;
3337
3338 u32 i;
3339
3340 for (i = 0; i < a.w * a.h; i++) {
3341 if (channels == 3)
3342 *target++ = ((icon[i * 3 + 0]) << 16) |
3343 ((icon[i * 3 + 1]) << 8) |
3344 ((icon[i * 3 + 2]) << 0) |
3345 (0xFF << 24);
3346
3347 else if (channels == 4)
3348 *target++ = ((icon[i * 4 + 0]) << 16) |
3349 ((icon[i * 4 + 1]) << 8) |
3350 ((icon[i * 4 + 2]) << 0) |
3351 ((icon[i * 4 + 3]) << 24);
3352 }
3353
3354 static Atom NET_WM_ICON = 0;
3355 if (NET_WM_ICON == 0)
3356 NET_WM_ICON = XInternAtom((Display*) win->src.display, "_NET_WM_ICON", False);
3357
3358 XChangeProperty((Display*) win->src.display, (Window) win->src.window,
3359 NET_WM_ICON,
3360 6, 32,
3361 PropModeReplace,
3362 (u8*) X11Icon,
3363 longCount);
3364
3365 RGFW_FREE(X11Icon);
3366
3367 XFlush((Display*) win->src.display);
3368 }
3369
3370 void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels) {
3371 assert(win != NULL);
3372
3373#ifndef RGFW_NO_X11_CURSOR
3374 XcursorImage* native = XcursorImageCreate(a.w, a.h);
3375 native->xhot = 0;
3376 native->yhot = 0;
3377
3378 u8* source = (u8*) image;
3379 XcursorPixel* target = native->pixels;
3380
3381 u32 i;
3382 for (i = 0; i < a.w * a.h; i++, target++, source += 4) {
3383 u8 alpha = 0xFF;
3384 if (channels == 4)
3385 alpha = source[3];
3386
3387 *target = (alpha << 24) | (((source[0] * alpha) / 255) << 16) | (((source[1] * alpha) / 255) << 8) | (((source[2] * alpha) / 255) << 0);
3388 }
3389
3390 Cursor cursor = XcursorImageLoadCursor((Display*) win->src.display, native);
3391 XDefineCursor((Display*) win->src.display, (Window) win->src.window, (Cursor) cursor);
3392
3393 XFreeCursor((Display*) win->src.display, (Cursor) cursor);
3394 XcursorImageDestroy(native);
3395#else
3396 RGFW_UNUSED(image) RGFW_UNUSED(a.w) RGFW_UNUSED(channels)
3397#endif
3398 }
3399
3400 void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) {
3401 assert(win != NULL);
3402
3403 XEvent event;
3404 XQueryPointer(win->src.display, DefaultRootWindow(win->src.display),
3405 &event.xbutton.root, &event.xbutton.window,
3406 &event.xbutton.x_root, &event.xbutton.y_root,
3407 &event.xbutton.x, &event.xbutton.y,
3408 &event.xbutton.state);
3409
3410 if (event.xbutton.x == v.x && event.xbutton.y == v.y)
3411 return;
3412
3413 XWarpPointer(win->src.display, None, win->src.window, 0, 0, 0, 0, (int) v.x - win->r.x, (int) v.y - win->r.y);
3414 }
3415
3416 RGFWDEF void RGFW_window_disableMouse(RGFW_window* win) {
3417 RGFW_UNUSED(win);
3418 }
3419
3420 void RGFW_window_setMouseDefault(RGFW_window* win) {
3421 RGFW_window_setMouseStandard(win, RGFW_MOUSE_ARROW);
3422 }
3423
3424 void RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {
3425 assert(win != NULL);
3426
3427 if (mouse > (sizeof(RGFW_mouseIconSrc) / sizeof(u8)))
3428 return;
3429
3430 mouse = RGFW_mouseIconSrc[mouse];
3431
3432 Cursor cursor = XCreateFontCursor((Display*) win->src.display, mouse);
3433 XDefineCursor((Display*) win->src.display, (Window) win->src.window, (Cursor) cursor);
3434
3435 XFreeCursor((Display*) win->src.display, (Cursor) cursor);
3436 }
3437
3438 void RGFW_window_hide(RGFW_window* win) {
3439 XMapWindow(win->src.display, win->src.window);
3440 }
3441
3442 void RGFW_window_show(RGFW_window* win) {
3443 XUnmapWindow(win->src.display, win->src.window);
3444 }
3445
3446 /*
3447 the majority function is sourced from GLFW
3448 */
3449 char* RGFW_readClipboard(size_t* size) {
3450 static Atom UTF8 = 0;
3451 if (UTF8 == 0)
3452 UTF8 = XInternAtom(RGFW_root->src.display, "UTF8_STRING", True);
3453
3454 XEvent event;
3455 int format;
3456 unsigned long N, sizeN;
3457 char* data, * s = NULL;
3458 Atom target;
3459 Atom CLIPBOARD = 0, XSEL_DATA = 0;
3460
3461 if (CLIPBOARD == 0) {
3462 CLIPBOARD = XInternAtom(RGFW_root->src.display, "CLIPBOARD", 0);
3463 XSEL_DATA = XInternAtom(RGFW_root->src.display, "XSEL_DATA", 0);
3464 }
3465
3466 XConvertSelection(RGFW_root->src.display, CLIPBOARD, UTF8, XSEL_DATA, RGFW_root->src.window, CurrentTime);
3467 XSync(RGFW_root->src.display, 0);
3468 XNextEvent(RGFW_root->src.display, &event);
3469
3470 if (event.type != SelectionNotify || event.xselection.selection != CLIPBOARD || event.xselection.property == 0)
3471 return NULL;
3472
3473 XGetWindowProperty(event.xselection.display, event.xselection.requestor,
3474 event.xselection.property, 0L, (~0L), 0, AnyPropertyType, &target,
3475 &format, &sizeN, &N, (unsigned char**) &data);
3476
3477 if (target == UTF8 || target == XA_STRING) {
3478 s = (char*)RGFW_MALLOC(sizeof(char) * sizeN);
3479 strncpy(s, data, sizeN);
3480 s[sizeN] = '\0';
3481 XFree(data);
3482 }
3483
3484 XDeleteProperty(event.xselection.display, event.xselection.requestor, event.xselection.property);
3485
3486 if (s != NULL && size != NULL)
3487 *size = sizeN;
3488
3489 return s;
3490 }
3491
3492 /*
3493 almost all of this function is sourced from GLFW
3494 */
3495 void RGFW_writeClipboard(const char* text, u32 textLen) {
3496 static Atom CLIPBOARD = 0,
3497 UTF8_STRING = 0,
3498 SAVE_TARGETS = 0,
3499 TARGETS = 0,
3500 MULTIPLE = 0,
3501 ATOM_PAIR = 0,
3502 CLIPBOARD_MANAGER = 0;
3503
3504 if (CLIPBOARD == 0) {
3505 CLIPBOARD = XInternAtom((Display*) RGFW_root->src.display, "CLIPBOARD", False);
3506 UTF8_STRING = XInternAtom((Display*) RGFW_root->src.display, "UTF8_STRING", False);
3507 SAVE_TARGETS = XInternAtom((Display*) RGFW_root->src.display, "SAVE_TARGETS", False);
3508 TARGETS = XInternAtom((Display*) RGFW_root->src.display, "TARGETS", False);
3509 MULTIPLE = XInternAtom((Display*) RGFW_root->src.display, "MULTIPLE", False);
3510 ATOM_PAIR = XInternAtom((Display*) RGFW_root->src.display, "ATOM_PAIR", False);
3511 CLIPBOARD_MANAGER = XInternAtom((Display*) RGFW_root->src.display, "CLIPBOARD_MANAGER", False);
3512 }
3513
3514 XSetSelectionOwner((Display*) RGFW_root->src.display, CLIPBOARD, (Window) RGFW_root->src.window, CurrentTime);
3515
3516 XConvertSelection((Display*) RGFW_root->src.display, CLIPBOARD_MANAGER, SAVE_TARGETS, None, (Window) RGFW_root->src.window, CurrentTime);
3517 for (;;) {
3518 XEvent event;
3519
3520 XNextEvent((Display*) RGFW_root->src.display, &event);
3521 if (event.type != SelectionRequest) {
3522 break;
3523 }
3524
3525 const XSelectionRequestEvent* request = &event.xselectionrequest;
3526
3527 XEvent reply = { SelectionNotify };
3528 reply.xselection.property = 0;
3529
3530 if (request->target == TARGETS) {
3531 const Atom targets[] = { TARGETS,
3532 MULTIPLE,
3533 UTF8_STRING,
3534 XA_STRING };
3535
3536 XChangeProperty((Display*) RGFW_root->src.display,
3537 request->requestor,
3538 request->property,
3539 4,
3540 32,
3541 PropModeReplace,
3542 (u8*) targets,
3543 sizeof(targets) / sizeof(targets[0]));
3544
3545 reply.xselection.property = request->property;
3546 }
3547
3548 if (request->target == MULTIPLE) {
3549 Atom* targets = NULL;
3550
3551 Atom actualType = 0;
3552 int actualFormat = 0;
3553 unsigned long count = 0, bytesAfter = 0;
3554
3555 XGetWindowProperty((Display*) RGFW_root->src.display, request->requestor, request->property, 0, LONG_MAX, False, ATOM_PAIR, &actualType, &actualFormat, &count, &bytesAfter, (u8**) &targets);
3556
3557 unsigned long i;
3558 for (i = 0; i < (u32)count; i += 2) {
3559 if (targets[i] == UTF8_STRING || targets[i] == XA_STRING) {
3560 XChangeProperty((Display*) RGFW_root->src.display,
3561 request->requestor,
3562 targets[i + 1],
3563 targets[i],
3564 8,
3565 PropModeReplace,
3566 (u8*) text,
3567 textLen);
3568 XFlush(RGFW_root->src.display);
3569 } else {
3570 targets[i + 1] = None;
3571 }
3572 }
3573
3574 XChangeProperty((Display*) RGFW_root->src.display,
3575 request->requestor,
3576 request->property,
3577 ATOM_PAIR,
3578 32,
3579 PropModeReplace,
3580 (u8*) targets,
3581 count);
3582
3583 XFlush(RGFW_root->src.display);
3584 XFree(targets);
3585
3586 reply.xselection.property = request->property;
3587 }
3588
3589 reply.xselection.display = request->display;
3590 reply.xselection.requestor = request->requestor;
3591 reply.xselection.selection = request->selection;
3592 reply.xselection.target = request->target;
3593 reply.xselection.time = request->time;
3594
3595 XSendEvent((Display*) RGFW_root->src.display, request->requestor, False, 0, &reply);
3596 XFlush(RGFW_root->src.display);
3597 }
3598 }
3599
3600 u8 RGFW_window_isFullscreen(RGFW_window* win) {
3601 assert(win != NULL);
3602
3603 XWindowAttributes windowAttributes;
3604 XGetWindowAttributes(win->src.display, (Window) win->src.window, &windowAttributes);
3605
3606 /* check if the window is visable */
3607 if (windowAttributes.map_state != IsViewable)
3608 return 0;
3609
3610 /* check if the window covers the full screen */
3611 return (windowAttributes.x == 0 && windowAttributes.y == 0 &&
3612 windowAttributes.width == XDisplayWidth(win->src.display, DefaultScreen(win->src.display)) &&
3613 windowAttributes.height == XDisplayHeight(win->src.display, DefaultScreen(win->src.display)));
3614 }
3615
3616 u8 RGFW_window_isHidden(RGFW_window* win) {
3617 assert(win != NULL);
3618
3619 XWindowAttributes windowAttributes;
3620 XGetWindowAttributes(win->src.display, (Window) win->src.window, &windowAttributes);
3621
3622 return (windowAttributes.map_state == IsUnmapped && !RGFW_window_isMinimized(win));
3623 }
3624
3625 u8 RGFW_window_isMinimized(RGFW_window* win) {
3626 assert(win != NULL);
3627
3628 static Atom prop = 0;
3629 if (prop == 0)
3630 prop = XInternAtom(win->src.display, "WM_STATE", False);
3631
3632 Atom actual_type;
3633 i32 actual_format;
3634 unsigned long nitems, bytes_after;
3635 unsigned char* prop_data;
3636
3637 i16 status = XGetWindowProperty(win->src.display, (Window) win->src.window, prop, 0, 2, False,
3638 AnyPropertyType, &actual_type, &actual_format,
3639 &nitems, &bytes_after, &prop_data);
3640
3641 if (status == Success && nitems >= 1 && *((int*) prop_data) == IconicState) {
3642 XFree(prop_data);
3643 return 1;
3644 }
3645
3646 if (prop_data != NULL)
3647 XFree(prop_data);
3648
3649 return 0;
3650 }
3651
3652 u8 RGFW_window_isMaximized(RGFW_window* win) {
3653 assert(win != NULL);
3654
3655 static Atom net_wm_state = 0;
3656 static Atom net_wm_state_maximized_horz = 0;
3657 static Atom net_wm_state_maximized_vert = 0;
3658
3659 if (net_wm_state == 0) {
3660 net_wm_state = XInternAtom(win->src.display, "_NET_WM_STATE", False);
3661 net_wm_state_maximized_vert = XInternAtom(win->src.display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
3662 net_wm_state_maximized_horz = XInternAtom(win->src.display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
3663 }
3664
3665 Atom actual_type;
3666 i32 actual_format;
3667 unsigned long nitems, bytes_after;
3668 unsigned char* prop_data;
3669
3670 i16 status = XGetWindowProperty(win->src.display, (Window) win->src.window, net_wm_state, 0, 1024, False,
3671 XA_ATOM, &actual_type, &actual_format,
3672 &nitems, &bytes_after, &prop_data);
3673
3674 if (status != Success) {
3675 if (prop_data != NULL)
3676 XFree(prop_data);
3677
3678 return 0;
3679 }
3680
3681 Atom* atoms = (Atom*) prop_data;
3682 u64 i;
3683 for (i = 0; i < nitems; ++i) {
3684 if (atoms[i] == net_wm_state_maximized_horz ||
3685 atoms[i] == net_wm_state_maximized_vert) {
3686 XFree(prop_data);
3687 return 1;
3688 }
3689 }
3690
3691 return 0;
3692 }
3693
3694 static void XGetSystemContentScale(Display* display, float* xscale, float* yscale) {
3695 float xdpi = 96.f, ydpi = 96.f;
3696
3697#ifndef RGFW_NO_DPI
3698 char* rms = XResourceManagerString(display);
3699 XrmDatabase db = NULL;
3700
3701 if (rms && db)
3702 db = XrmGetStringDatabase(rms);
3703
3704 if (db == 0) {
3705 *xscale = xdpi / 96.f;
3706 *yscale = ydpi / 96.f;
3707 return;
3708 }
3709
3710 XrmValue value;
3711 char* type = NULL;
3712
3713 if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) && type && strncmp(type, "String", 7) == 0)
3714 xdpi = ydpi = atof(value.addr);
3715 XrmDestroyDatabase(db);
3716#endif
3717
3718 * xscale = xdpi / 96.f;
3719 *yscale = ydpi / 96.f;
3720 }
3721
3722 RGFW_monitor RGFW_XCreateMonitor(i32 screen) {
3723 RGFW_monitor monitor;
3724
3725 Display* display = XOpenDisplay(NULL);
3726
3727 RGFW_area size = RGFW_getScreenSize();
3728
3729 monitor.rect = RGFW_RECT(0, 0, size.w, size.h);
3730 monitor.physW = DisplayWidthMM(display, screen);
3731 monitor.physH = DisplayHeightMM(display, screen);
3732
3733 XGetSystemContentScale(display, &monitor.scaleX, &monitor.scaleY);
3734 XRRScreenResources* sr = XRRGetScreenResourcesCurrent(display, RootWindow(display, screen));
3735
3736 XRRCrtcInfo* ci = NULL;
3737 int crtc = screen;
3738
3739 if (sr->ncrtc > crtc) {
3740 ci = XRRGetCrtcInfo(display, sr, sr->crtcs[crtc]);
3741 }
3742
3743 if (ci == NULL) {
3744 float dpi_width = round((double)monitor.rect.w/(((double)monitor.physW)/25.4));
3745 float dpi_height = round((double)monitor.rect.h/(((double)monitor.physH)/25.4));
3746
3747 monitor.scaleX = (float) (dpi_width) / (float) 96;
3748 monitor.scaleY = (float) (dpi_height) / (float) 96;
3749 XRRFreeScreenResources(sr);
3750 XCloseDisplay(display);
3751 return monitor;
3752 }
3753
3754 XRROutputInfo* info = XRRGetOutputInfo (display, sr, sr->outputs[screen]);
3755 monitor.physW = info->mm_width;
3756 monitor.physH = info->mm_height;
3757
3758 monitor.rect.x = ci->x;
3759 monitor.rect.y = ci->y;
3760 monitor.rect.w = ci->width;
3761 monitor.rect.h = ci->height;
3762
3763 float dpi_width = round((double)monitor.rect.w/(((double)monitor.physW)/25.4));
3764 float dpi_height = round((double)monitor.rect.h/(((double)monitor.physH)/25.4));
3765
3766 monitor.scaleX = (float) (dpi_width) / (float) 96;
3767 monitor.scaleY = (float) (dpi_height) / (float) 96;
3768
3769 if (monitor.scaleX > 1 && monitor.scaleX < 1.1)
3770 monitor.scaleX = 1;
3771
3772 if (monitor.scaleY > 1 && monitor.scaleY < 1.1)
3773 monitor.scaleY = 1;
3774
3775 XRRFreeCrtcInfo(ci);
3776 XRRFreeScreenResources(sr);
3777
3778 XCloseDisplay(display);
3779
3780 return monitor;
3781 }
3782
3783 RGFW_monitor RGFW_monitors[6];
3784 RGFW_monitor* RGFW_getMonitors(void) {
3785 size_t i;
3786 for (i = 0; i < (size_t)ScreenCount(RGFW_root->src.display) && i < 6; i++)
3787 RGFW_monitors[i] = RGFW_XCreateMonitor(i);
3788
3789 return RGFW_monitors;
3790 }
3791
3792 RGFW_monitor RGFW_getPrimaryMonitor(void) {
3793 assert(RGFW_root != NULL);
3794
3795 i32 primary = -1;
3796 Window root = DefaultRootWindow(RGFW_root->src.display);
3797 XRRScreenResources* res = XRRGetScreenResources(RGFW_root->src.display, root);
3798
3799 for (int i = 0; i < res->noutput; i++) {
3800 XRROutputInfo* output_info = XRRGetOutputInfo(RGFW_root->src.display, res, res->outputs[i]);
3801 if (output_info->connection == RR_Connected && output_info->crtc) {
3802 XRRCrtcInfo* crtc_info = XRRGetCrtcInfo(RGFW_root->src.display, res, output_info->crtc);
3803 if (crtc_info->mode != None && crtc_info->x == 0 && crtc_info->y == 0) {
3804 primary = i;
3805 XRRFreeCrtcInfo(crtc_info);
3806 XRRFreeOutputInfo(output_info);
3807 break;
3808 }
3809 XRRFreeCrtcInfo(crtc_info);
3810 }
3811 XRRFreeOutputInfo(output_info);
3812 }
3813
3814 XRRFreeScreenResources(res);
3815
3816 return RGFW_XCreateMonitor(primary);
3817 }
3818
3819 RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {
3820 return RGFW_XCreateMonitor(DefaultScreen(win->src.display));
3821 }
3822
3823 #ifdef RGFW_OPENGL
3824 void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
3825 if (win == NULL)
3826 glXMakeCurrent((Display*) NULL, (Drawable)NULL, (GLXContext) NULL);
3827 else
3828 glXMakeCurrent((Display*) win->src.display, (Drawable) win->src.window, (GLXContext) win->src.ctx);
3829 }
3830 #endif
3831
3832
3833 void RGFW_window_swapBuffers(RGFW_window* win) {
3834 assert(win != NULL);
3835
3836 /* clear the window*/
3837 if (!(win->_winArgs & RGFW_NO_CPU_RENDER)) {
3838#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
3839 #ifdef RGFW_OSMESA
3840 RGFW_OSMesa_reorganize();
3841 #endif
3842 RGFW_area area = RGFW_bufferSize;
3843
3844#ifndef RGFW_X11_DONT_CONVERT_BGR
3845 win->src.bitmap->data = (char*) win->buffer;
3846 u32 x, y;
3847 for (y = 0; y < (u32)win->r.h; y++) {
3848 for (x = 0; x < (u32)win->r.w; x++) {
3849 u32 index = (y * 4 * area.w) + x * 4;
3850
3851 u8 red = win->src.bitmap->data[index];
3852 win->src.bitmap->data[index] = win->buffer[index + 2];
3853 win->src.bitmap->data[index + 2] = red;
3854
3855 }
3856 }
3857#endif
3858 XPutImage(win->src.display, (Window) win->src.window, win->src.gc, win->src.bitmap, 0, 0, 0, 0, RGFW_bufferSize.w, RGFW_bufferSize.h);
3859#endif
3860 }
3861
3862 if (!(win->_winArgs & RGFW_NO_GPU_RENDER)) {
3863 #ifdef RGFW_EGL
3864 eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface);
3865 #elif defined(RGFW_OPENGL)
3866 glXSwapBuffers((Display*) win->src.display, (Window) win->src.window);
3867 #endif
3868 }
3869 }
3870
3871 #if !defined(RGFW_EGL)
3872 void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) {
3873 assert(win != NULL);
3874
3875 #if defined(RGFW_OPENGL)
3876 ((PFNGLXSWAPINTERVALEXTPROC) glXGetProcAddress((GLubyte*) "glXSwapIntervalEXT"))((Display*) win->src.display, (Window) win->src.window, swapInterval);
3877 #else
3878 RGFW_UNUSED(swapInterval);
3879 #endif
3880 }
3881 #endif
3882
3883
3884 void RGFW_window_close(RGFW_window* win) {
3885 /* ungrab pointer if it was grabbed */
3886 if (win->_winArgs & RGFW_HOLD_MOUSE)
3887 XUngrabPointer(win->src.display, CurrentTime);
3888
3889 assert(win != NULL);
3890#ifdef RGFW_EGL
3891 RGFW_closeEGL(win);
3892#endif
3893
3894#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
3895 if (win->buffer != NULL) {
3896 XDestroyImage((XImage*) win->src.bitmap);
3897 XFreeGC(win->src.display, win->src.gc);
3898 }
3899#endif
3900
3901 if ((Display*) win->src.display) {
3902#ifdef RGFW_OPENGL
3903 glXDestroyContext((Display*) win->src.display, win->src.ctx);
3904#endif
3905
3906 if (win == RGFW_root)
3907 RGFW_root = NULL;
3908
3909 if ((Drawable) win->src.window)
3910 XDestroyWindow((Display*) win->src.display, (Drawable) win->src.window); /*!< close the window*/
3911
3912 XCloseDisplay((Display*) win->src.display); /*!< kill the display*/
3913 }
3914
3915#ifdef RGFW_ALLOC_DROPFILES
3916 {
3917 u32 i;
3918 for (i = 0; i < RGFW_MAX_DROPS; i++)
3919 RGFW_FREE(win->event.droppedFiles[i]);
3920
3921
3922 RGFW_FREE(win->event.droppedFiles);
3923 }
3924#endif
3925
3926 RGFW_windowsOpen--;
3927#if !defined(RGFW_NO_X11_CURSOR_PRELOAD) && !defined(RGFW_NO_X11_CURSOR)
3928 if (X11Cursorhandle != NULL && RGFW_windowsOpen <= 0) {
3929 dlclose(X11Cursorhandle);
3930
3931 X11Cursorhandle = NULL;
3932 }
3933#endif
3934#if !defined(RGFW_NO_X11_XI_PRELOAD)
3935 if (X11Xihandle != NULL && RGFW_windowsOpen <= 0) {
3936 dlclose(X11Xihandle);
3937
3938 X11Xihandle = NULL;
3939 }
3940#endif
3941
3942 if (RGFW_libxshape != NULL && RGFW_windowsOpen <= 0) {
3943 dlclose(RGFW_libxshape);
3944 RGFW_libxshape = NULL;
3945 }
3946
3947 if (RGFW_windowsOpen <= 0) {
3948 if (RGFW_eventWait_forceStop[0] || RGFW_eventWait_forceStop[1]){
3949 close(RGFW_eventWait_forceStop[0]);
3950 close(RGFW_eventWait_forceStop[1]);
3951 }
3952
3953 u8 i;
3954 for (i = 0; i < RGFW_joystickCount; i++)
3955 close(RGFW_joysticks[i]);
3956 }
3957
3958 /* set cleared display / window to NULL for error checking */
3959 win->src.display = (Display*) 0;
3960 win->src.window = (Window) 0;
3961
3962 RGFW_FREE(win); /*!< free collected window data */
3963 }
3964
3965
3966/*
3967 End of X11 linux / unix defines
3968*/
3969
3970#endif /* RGFW_X11 */
3971
3972
3973/* wayland or X11 defines*/
3974#if defined(RGFW_WAYLAND) || defined(RGFW_X11)
3975#include <fcntl.h>
3976#include <poll.h>
3977#include <unistd.h>
3978 u16 RGFW_registerJoystickF(RGFW_window* win, char* file) {
3979 assert(win != NULL);
3980
3981#ifdef __linux__
3982
3983 i32 js = open(file, O_RDONLY);
3984
3985 if (js && RGFW_joystickCount < 4) {
3986 RGFW_joystickCount++;
3987
3988 RGFW_joysticks[RGFW_joystickCount - 1] = open(file, O_RDONLY);
3989
3990 u8 i;
3991 for (i = 0; i < 16; i++)
3992 RGFW_jsPressed[RGFW_joystickCount - 1][i] = 0;
3993
3994 }
3995
3996 else {
3997#ifdef RGFW_PRINT_ERRORS
3998 RGFW_error = 1;
3999 fprintf(stderr, "Error RGFW_registerJoystickF : Cannot open file %s\n", file);
4000#endif
4001 }
4002
4003 return RGFW_joystickCount - 1;
4004#endif
4005 }
4006
4007 u16 RGFW_registerJoystick(RGFW_window* win, i32 jsNumber) {
4008 assert(win != NULL);
4009
4010#ifdef __linux__
4011 char file[15];
4012 sprintf(file, "/dev/input/js%i", jsNumber);
4013
4014 return RGFW_registerJoystickF(win, file);
4015#endif
4016 }
4017
4018 void RGFW_stopCheckEvents(void) {
4019 RGFW_eventWait_forceStop[2] = 1;
4020 while (1) {
4021 const char byte = 0;
4022 const ssize_t result = write(RGFW_eventWait_forceStop[1], &byte, 1);
4023 if (result == 1 || result == -1)
4024 break;
4025 }
4026 }
4027
4028 void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) {
4029 if (waitMS == 0)
4030 return;
4031
4032 u8 i;
4033
4034 if (RGFW_eventWait_forceStop[0] == 0 || RGFW_eventWait_forceStop[1] == 0) {
4035 if (pipe(RGFW_eventWait_forceStop) != -1) {
4036 fcntl(RGFW_eventWait_forceStop[0], F_GETFL, 0);
4037 fcntl(RGFW_eventWait_forceStop[0], F_GETFD, 0);
4038 fcntl(RGFW_eventWait_forceStop[1], F_GETFL, 0);
4039 fcntl(RGFW_eventWait_forceStop[1], F_GETFD, 0);
4040 }
4041 }
4042
4043 struct pollfd fds[] = {
4044 #ifdef RGFW_WAYLAND
4045 { wl_display_get_fd(win->src.display), POLLIN, 0 },
4046 #else
4047 { ConnectionNumber(win->src.display), POLLIN, 0 },
4048 #endif
4049 { RGFW_eventWait_forceStop[0], POLLIN, 0 },
4050 #ifdef __linux__ /* blank space for 4 joystick files*/
4051 { -1, POLLIN, 0 }, {-1, POLLIN, 0 }, {-1, POLLIN, 0 }, {-1, POLLIN, 0}
4052 #endif
4053 };
4054
4055 u8 index = 2;
4056
4057 #if defined(__linux__)
4058 for (i = 0; i < RGFW_joystickCount; i++) {
4059 if (RGFW_joysticks[i] == 0)
4060 continue;
4061
4062 fds[index].fd = RGFW_joysticks[i];
4063 index++;
4064 }
4065 #endif
4066
4067
4068 u64 start = RGFW_getTimeNS();
4069
4070 #ifdef RGFW_WAYLAND
4071 while (wl_display_dispatch(win->src.display) <= 0 && waitMS >= -1) {
4072 #else
4073 while (XPending(win->src.display) == 0 && waitMS >= -1) {
4074 #endif
4075 if (poll(fds, index, waitMS) <= 0)
4076 break;
4077
4078 if (waitMS > 0) {
4079 waitMS -= (RGFW_getTimeNS() - start) / 1e+6;
4080 }
4081 }
4082
4083 /* drain any data in the stop request */
4084 if (RGFW_eventWait_forceStop[2]) {
4085 char data[64];
4086 (void)!read(RGFW_eventWait_forceStop[0], data, sizeof(data));
4087
4088 RGFW_eventWait_forceStop[2] = 0;
4089 }
4090 }
4091
4092 u64 RGFW_getTimeNS(void) {
4093 struct timespec ts = { 0 };
4094 clock_gettime(1, &ts);
4095 unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec;
4096
4097 return nanoSeconds;
4098 }
4099
4100 u64 RGFW_getTime(void) {
4101 struct timespec ts = { 0 };
4102 clock_gettime(1, &ts);
4103 unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec;
4104
4105 return (double)(nanoSeconds) * 1e-9;
4106 }
4107#endif /* end of wayland or X11 time defines*/
4108
4109
4110/*
4111
4112 Start of Wayland defines
4113
4114
4115*/
4116
4117#ifdef RGFW_WAYLAND
4118/*
4119Wayland TODO:
4120- fix RGFW_keyPressed lock state
4121
4122 RGFW_windowMoved, the window was moved (by the user)
4123 RGFW_windowResized the window was resized (by the user), [on webASM this means the browser was resized]
4124 RGFW_windowRefresh The window content needs to be refreshed
4125
4126 RGFW_dnd a file has been dropped into the window
4127 RGFW_dnd_init
4128
4129- window args:
4130 #define RGFW_NO_RESIZE the window cannot be resized by the user
4131 #define RGFW_ALLOW_DND the window supports drag and drop
4132 #define RGFW_SCALE_TO_MONITOR scale the window to the screen
4133
4134- other missing functions functions ("TODO wayland") (~30 functions)
4135- fix buffer rendering weird behavior
4136*/
4137 #include <errno.h>
4138 #include <unistd.h>
4139 #include <sys/mman.h>
4140 #include <xkbcommon/xkbcommon.h>
4141 #include <xkbcommon/xkbcommon-keysyms.h>
4142 #include <dirent.h>
4143 #include <linux/kd.h>
4144 #include <wayland-cursor.h>
4145
4146RGFW_window* RGFW_key_win = NULL;
4147
4148void RGFW_eventPipe_push(RGFW_window* win, RGFW_Event event) {
4149 if (win == NULL) {
4150 win = RGFW_key_win;
4151
4152 if (win == NULL) return;
4153 }
4154
4155 if (win->src.eventLen >= (i32)(sizeof(win->src.events) / sizeof(win->src.events[0])))
4156 return;
4157
4158 win->src.events[win->src.eventLen] = event;
4159 win->src.eventLen += 1;
4160}
4161
4162RGFW_Event RGFW_eventPipe_pop(RGFW_window* win) {
4163 RGFW_Event ev;
4164 ev.type = 0;
4165
4166 if (win->src.eventLen > -1)
4167 win->src.eventLen -= 1;
4168
4169 if (win->src.eventLen >= 0)
4170 ev = win->src.events[win->src.eventLen];
4171
4172 return ev;
4173}
4174
4175/* wayland global garbage (wayland bad, X11 is fine (ish) (not really)) */
4176#include "xdg-shell.h"
4177#include "xdg-decoration-unstable-v1.h"
4178
4179struct xdg_wm_base *xdg_wm_base;
4180struct wl_compositor* RGFW_compositor = NULL;
4181struct wl_shm* shm = NULL;
4182struct wl_shell* RGFW_shell = NULL;
4183static struct wl_seat *seat = NULL;
4184static struct xkb_context *xkb_context;
4185static struct xkb_keymap *keymap = NULL;
4186static struct xkb_state *xkb_state = NULL;
4187enum zxdg_toplevel_decoration_v1_mode client_preferred_mode, RGFW_current_mode;
4188static struct zxdg_decoration_manager_v1 *decoration_manager = NULL;
4189
4190struct wl_cursor_theme* RGFW_wl_cursor_theme = NULL;
4191struct wl_surface* RGFW_cursor_surface = NULL;
4192struct wl_cursor_image* RGFW_cursor_image = NULL;
4193
4194static void xdg_wm_base_ping_handler(void *data,
4195 struct xdg_wm_base *wm_base, uint32_t serial)
4196{
4197 RGFW_UNUSED(data);
4198 xdg_wm_base_pong(wm_base, serial);
4199}
4200
4201static const struct xdg_wm_base_listener xdg_wm_base_listener = {
4202 .ping = xdg_wm_base_ping_handler,
4203};
4204
4205b8 RGFW_wl_configured = 0;
4206
4207static void xdg_surface_configure_handler(void *data,
4208 struct xdg_surface *xdg_surface, uint32_t serial)
4209{
4210 RGFW_UNUSED(data);
4211 xdg_surface_ack_configure(xdg_surface, serial);
4212 #ifdef RGFW_DEBUG
4213 printf("Surface configured\n");
4214 #endif
4215 RGFW_wl_configured = 1;
4216}
4217
4218static const struct xdg_surface_listener xdg_surface_listener = {
4219 .configure = xdg_surface_configure_handler,
4220};
4221
4222static void xdg_toplevel_configure_handler(void *data,
4223 struct xdg_toplevel *toplevel, int32_t width, int32_t height,
4224 struct wl_array *states)
4225{
4226 RGFW_UNUSED(data); RGFW_UNUSED(toplevel); RGFW_UNUSED(states)
4227 fprintf(stderr, "XDG toplevel configure: %dx%d\n", width, height);
4228}
4229
4230static void xdg_toplevel_close_handler(void *data,
4231 struct xdg_toplevel *toplevel)
4232{
4233 RGFW_UNUSED(data);
4234 RGFW_window* win = (RGFW_window*)xdg_toplevel_get_user_data(toplevel);
4235 if (win == NULL)
4236 win = RGFW_key_win;
4237
4238 RGFW_Event ev;
4239 ev.type = RGFW_quit;
4240
4241 RGFW_eventPipe_push(win, ev);
4242
4243 RGFW_windowQuitCallback(win);
4244}
4245
4246static void shm_format_handler(void *data,
4247 struct wl_shm *shm, uint32_t format)
4248{
4249 RGFW_UNUSED(data); RGFW_UNUSED(shm);
4250 fprintf(stderr, "Format %d\n", format);
4251}
4252
4253static const struct wl_shm_listener shm_listener = {
4254 .format = shm_format_handler,
4255};
4256
4257static const struct xdg_toplevel_listener xdg_toplevel_listener = {
4258 .configure = xdg_toplevel_configure_handler,
4259 .close = xdg_toplevel_close_handler,
4260};
4261
4262RGFW_window* RGFW_mouse_win = NULL;
4263
4264static void pointer_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) {
4265 RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(serial); RGFW_UNUSED(surface_x); RGFW_UNUSED(surface_y);
4266 RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
4267 RGFW_mouse_win = win;
4268
4269 RGFW_Event ev;
4270 ev.type = RGFW_mouseEnter;
4271 ev.point = win->event.point;
4272
4273 RGFW_eventPipe_push(win, ev);
4274
4275 RGFW_mouseNotifyCallBack(win, win->event.point, RGFW_TRUE);
4276}
4277static void pointer_leave(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface) {
4278 RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(serial); RGFW_UNUSED(surface);
4279 RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
4280 if (RGFW_mouse_win == win)
4281 RGFW_mouse_win = NULL;
4282
4283 RGFW_Event ev;
4284 ev.type = RGFW_mouseLeave;
4285 ev.point = win->event.point;
4286 RGFW_eventPipe_push(win, ev);
4287
4288 RGFW_mouseNotifyCallBack(win, win->event.point, RGFW_FALSE);
4289}
4290static void pointer_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t x, wl_fixed_t y) {
4291 RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(x); RGFW_UNUSED(y);
4292
4293 assert(RGFW_mouse_win != NULL);
4294
4295 RGFW_Event ev;
4296 ev.type = RGFW_mousePosChanged;
4297 ev.point = RGFW_POINT(wl_fixed_to_double(x), wl_fixed_to_double(y));
4298 RGFW_eventPipe_push(RGFW_mouse_win, ev);
4299
4300 RGFW_mousePosCallback(RGFW_mouse_win, RGFW_POINT(wl_fixed_to_double(x), wl_fixed_to_double(y)));
4301}
4302static void pointer_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) {
4303 RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(serial);
4304 assert(RGFW_mouse_win != NULL);
4305
4306 u32 b = (button - 0x110) + 1;
4307
4308 /* flip right and middle button codes */
4309 if (b == 2) b = 3;
4310 else if (b == 3) b = 2;
4311
4312 RGFW_mouseButtons[b].prev = RGFW_mouseButtons[b].current;
4313 RGFW_mouseButtons[b].current = state;
4314
4315 RGFW_Event ev;
4316 ev.type = RGFW_mouseButtonPressed + state;
4317 ev.button = b;
4318 RGFW_eventPipe_push(RGFW_mouse_win, ev);
4319
4320 RGFW_mouseButtonCallback(RGFW_mouse_win, b, 0, state);
4321}
4322static void pointer_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value) {
4323 RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(axis);
4324 assert(RGFW_mouse_win != NULL);
4325
4326 double scroll = wl_fixed_to_double(value);
4327
4328 RGFW_Event ev;
4329 ev.type = RGFW_mouseButtonPressed;
4330 ev.button = RGFW_mouseScrollUp + (scroll < 0);
4331 RGFW_eventPipe_push(RGFW_mouse_win, ev);
4332
4333 RGFW_mouseButtonCallback(RGFW_mouse_win, RGFW_mouseScrollUp + (scroll < 0), scroll, 1);
4334}
4335
4336void RGFW_doNothing(void) { }
4337static struct wl_pointer_listener pointer_listener = (struct wl_pointer_listener){&pointer_enter, &pointer_leave, &pointer_motion, &pointer_button, &pointer_axis, (void*)&RGFW_doNothing, (void*)&RGFW_doNothing, (void*)&RGFW_doNothing, (void*)&RGFW_doNothing, (void*)&RGFW_doNothing, (void*)&RGFW_doNothing};
4338
4339static void keyboard_keymap (void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size) {
4340 RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(format);
4341
4342 char *keymap_string = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0);
4343 xkb_keymap_unref (keymap);
4344 keymap = xkb_keymap_new_from_string (xkb_context, keymap_string, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
4345
4346 munmap (keymap_string, size);
4347 close (fd);
4348 xkb_state_unref (xkb_state);
4349 xkb_state = xkb_state_new (keymap);
4350}
4351static void keyboard_enter (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) {
4352 RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(keys);
4353
4354 RGFW_key_win = (RGFW_window*)wl_surface_get_user_data(surface);
4355
4356 RGFW_Event ev;
4357 ev.type = RGFW_focusIn;
4358 ev.inFocus = RGFW_TRUE;
4359 RGFW_key_win->event.inFocus = RGFW_TRUE;
4360
4361 RGFW_eventPipe_push((RGFW_window*)RGFW_mouse_win, ev);
4362
4363 RGFW_focusCallback(RGFW_key_win, RGFW_TRUE);
4364}
4365static void keyboard_leave (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) {
4366 RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial);
4367
4368 RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface);
4369 if (RGFW_key_win == win)
4370 RGFW_key_win = NULL;
4371
4372 RGFW_Event ev;
4373 ev.type = RGFW_focusOut;
4374 ev.inFocus = RGFW_FALSE;
4375 win->event.inFocus = RGFW_FALSE;
4376 RGFW_eventPipe_push(win, ev);
4377
4378 RGFW_focusCallback(win, RGFW_FALSE);
4379}
4380static void keyboard_key (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) {
4381 RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time);
4382
4383 assert(RGFW_key_win != NULL);
4384
4385 xkb_keysym_t keysym = xkb_state_key_get_one_sym (xkb_state, key+8);
4386 char name[16];
4387 xkb_keysym_get_name(keysym, name, 16);
4388
4389 u32 RGFW_key = RGFW_apiKeyCodeToRGFW(key);
4390 RGFW_keyboard[RGFW_key].prev = RGFW_keyboard[RGFW_key].current;
4391 RGFW_keyboard[RGFW_key].current = state;
4392 RGFW_Event ev;
4393 ev.type = RGFW_keyPressed + state;
4394 ev.keyCode = RGFW_key;
4395 strcpy(ev.keyName, name);
4396 ev.repeat = RGFW_isHeld(RGFW_key_win, RGFW_key);
4397 RGFW_eventPipe_push(RGFW_key_win, ev);
4398
4399 RGFW_updateLockState(RGFW_key_win, xkb_keymap_mod_get_index(keymap, "Lock"), xkb_keymap_mod_get_index(keymap, "Mod2"));
4400
4401 RGFW_keyCallback(RGFW_key_win, RGFW_key, name, RGFW_key_win->event.lockState, state);
4402}
4403static void keyboard_modifiers (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) {
4404 RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time);
4405 xkb_state_update_mask (xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
4406}
4407static struct wl_keyboard_listener keyboard_listener = {&keyboard_keymap, &keyboard_enter, &keyboard_leave, &keyboard_key, &keyboard_modifiers, (void*)&RGFW_doNothing};
4408
4409static void seat_capabilities (void *data, struct wl_seat *seat, uint32_t capabilities) {
4410 RGFW_UNUSED(data);
4411
4412 if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
4413 struct wl_pointer *pointer = wl_seat_get_pointer (seat);
4414 wl_pointer_add_listener (pointer, &pointer_listener, NULL);
4415 }
4416 if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) {
4417 struct wl_keyboard *keyboard = wl_seat_get_keyboard (seat);
4418 wl_keyboard_add_listener (keyboard, &keyboard_listener, NULL);
4419 }
4420}
4421static struct wl_seat_listener seat_listener = {&seat_capabilities, (void*)&RGFW_doNothing};
4422
4423static void wl_global_registry_handler(void *data,
4424 struct wl_registry *registry, uint32_t id, const char *interface,
4425 uint32_t version)
4426{
4427 RGFW_UNUSED(data); RGFW_UNUSED(version);
4428
4429 if (strcmp(interface, "wl_compositor") == 0) {
4430 RGFW_compositor = wl_registry_bind(registry,
4431 id, &wl_compositor_interface, 4);
4432 } else if (strcmp(interface, "xdg_wm_base") == 0) {
4433 xdg_wm_base = wl_registry_bind(registry,
4434 id, &xdg_wm_base_interface, 1);
4435 } else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) {
4436 decoration_manager = wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1);
4437 } else if (strcmp(interface, "wl_shm") == 0) {
4438 shm = wl_registry_bind(registry,
4439 id, &wl_shm_interface, 1);
4440 wl_shm_add_listener(shm, &shm_listener, NULL);
4441 } else if (strcmp(interface,"wl_seat") == 0) {
4442 seat = wl_registry_bind(registry, id, &wl_seat_interface, 1);
4443 wl_seat_add_listener(seat, &seat_listener, NULL);
4444 }
4445
4446 else {
4447 #ifdef RGFW_DEBUG
4448 printf("did not register %s\n", interface);
4449 return;
4450 #endif
4451 }
4452
4453 #ifdef RGFW_DEBUG
4454 printf("registered %s\n", interface);
4455 #endif
4456}
4457
4458static void wl_global_registry_remove(void *data, struct wl_registry *registry, uint32_t name) { RGFW_UNUSED(data); RGFW_UNUSED(registry); RGFW_UNUSED(name); }
4459static const struct wl_registry_listener registry_listener = {
4460 .global = wl_global_registry_handler,
4461 .global_remove = wl_global_registry_remove,
4462};
4463
4464static const char *get_mode_name(enum zxdg_toplevel_decoration_v1_mode mode) {
4465 switch (mode) {
4466 case ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE:
4467 return "client-side decorations";
4468 case ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE:
4469 return "server-side decorations";
4470 }
4471 abort();
4472}
4473
4474
4475static void decoration_handle_configure(void *data,
4476 struct zxdg_toplevel_decoration_v1 *decoration,
4477 enum zxdg_toplevel_decoration_v1_mode mode) {
4478 RGFW_UNUSED(data); RGFW_UNUSED(decoration);
4479 printf("Using %s\n", get_mode_name(mode));
4480 RGFW_current_mode = mode;
4481}
4482
4483static const struct zxdg_toplevel_decoration_v1_listener decoration_listener = {
4484 .configure = decoration_handle_configure,
4485};
4486
4487static void randname(char *buf) {
4488 struct timespec ts;
4489 clock_gettime(CLOCK_REALTIME, &ts);
4490 long r = ts.tv_nsec;
4491 for (int i = 0; i < 6; ++i) {
4492 buf[i] = 'A'+(r&15)+(r&16)*2;
4493 r >>= 5;
4494 }
4495}
4496
4497static int anonymous_shm_open(void) {
4498 char name[] = "/RGFW-wayland-XXXXXX";
4499 int retries = 100;
4500
4501 do {
4502 randname(name + strlen(name) - 6);
4503
4504 --retries;
4505 // shm_open guarantees that O_CLOEXEC is set
4506 int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
4507 if (fd >= 0) {
4508 shm_unlink(name);
4509 return fd;
4510 }
4511 } while (retries > 0 && errno == EEXIST);
4512
4513 return -1;
4514}
4515
4516int create_shm_file(off_t size) {
4517 int fd = anonymous_shm_open();
4518 if (fd < 0) {
4519 return fd;
4520 }
4521
4522 if (ftruncate(fd, size) < 0) {
4523 close(fd);
4524 return -1;
4525 }
4526
4527 return fd;
4528}
4529
4530static void wl_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) {
4531 #ifdef RGFW_BUFFER
4532 RGFW_window* win = (RGFW_window*)data;
4533 if ((win->_winArgs & RGFW_NO_CPU_RENDER))
4534 return;
4535
4536 #ifndef RGFW_X11_DONT_CONVERT_BGR
4537 u32 x, y;
4538 for (y = 0; y < (u32)win->r.h; y++) {
4539 for (x = 0; x < (u32)win->r.w; x++) {
4540 u32 index = (y * 4 * win->r.w) + x * 4;
4541
4542 u8 red = win->buffer[index];
4543 win->buffer[index] = win->buffer[index + 2];
4544 win->buffer[index + 2] = red;
4545
4546 }
4547 }
4548 #endif
4549
4550 wl_surface_attach(win->src.surface, win->src.wl_buffer, 0, 0);
4551 wl_surface_damage_buffer(win->src.surface, 0, 0, win->r.w, win->r.h);
4552 wl_surface_commit(win->src.surface);
4553 #endif
4554}
4555
4556static const struct wl_callback_listener wl_surface_frame_listener = {
4557 .done = wl_surface_frame_done,
4558};
4559
4560
4561 /* normal wayland RGFW stuff */
4562
4563 RGFW_area RGFW_getScreenSize(void) {
4564 RGFW_area area = {};
4565
4566 if (RGFW_root != NULL)
4567 /* this isn't right but it's here for buffers */
4568 area = RGFW_AREA(RGFW_root->r.w, RGFW_root->r.h);
4569
4570 /* TODO wayland */
4571 return area;
4572 }
4573
4574 void RGFW_releaseCursor(RGFW_window* win) {
4575 RGFW_UNUSED(win);
4576 }
4577
4578 void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) {
4579 RGFW_UNUSED(win); RGFW_UNUSED(r);
4580
4581 /* TODO wayland */
4582 }
4583
4584
4585 RGFWDEF void RGFW_init_buffer(RGFW_window* win);
4586 void RGFW_init_buffer(RGFW_window* win) {
4587 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
4588 size_t size = win->r.w * win->r.h * 4;
4589 int fd = create_shm_file(size);
4590 if (fd < 0) {
4591 fprintf(stderr, "Failed to create a buffer. size: %ld\n", size);
4592 exit(1);
4593 }
4594
4595 win->buffer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
4596 if (win->buffer == MAP_FAILED) {
4597 fprintf(stderr, "mmap failed!\n");
4598 close(fd);
4599 exit(1);
4600 }
4601
4602 struct wl_shm_pool* pool = wl_shm_create_pool(shm, fd, size);
4603 win->src.wl_buffer = wl_shm_pool_create_buffer(pool, 0, win->r.w, win->r.h, win->r.w * 4,
4604 WL_SHM_FORMAT_ARGB8888);
4605 wl_shm_pool_destroy(pool);
4606
4607 close(fd);
4608
4609 wl_surface_attach(win->src.surface, win->src.wl_buffer, 0, 0);
4610 wl_surface_commit(win->src.surface);
4611
4612 u8 color[] = {0x00, 0x00, 0x00, 0xFF};
4613
4614 size_t i;
4615 for (i = 0; i < size; i += 4) {
4616 memcpy(&win->buffer[i], color, 4);
4617 }
4618
4619 #if defined(RGFW_OSMESA)
4620 win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL);
4621 OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, win->r.w, win->r.h);
4622 #endif
4623 #else
4624 RGFW_UNUSED(win);
4625 #endif
4626 }
4627
4628
4629 RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) {
4630 RGFW_window* win = RGFW_window_basic_init(rect, args);
4631
4632 fprintf(stderr, "Warning: RGFW Wayland support is experimental\n");
4633
4634 win->src.display = wl_display_connect(NULL);
4635 if (win->src.display == NULL) {
4636 #ifdef RGFW_DEBUG
4637 fprintf(stderr, "Failed to load Wayland display\n");
4638 #endif
4639 return NULL;
4640 }
4641
4642 struct wl_registry *registry = wl_display_get_registry(win->src.display);
4643 wl_registry_add_listener(registry, &registry_listener, NULL);
4644
4645 wl_display_dispatch(win->src.display);
4646 wl_display_roundtrip(win->src.display);
4647
4648 if (RGFW_compositor == NULL) {
4649 #ifdef RGFW_DEBUG
4650 fprintf(stderr, "Can't find compositor.\n");
4651 #endif
4652
4653 return NULL;
4654 }
4655
4656 if (RGFW_wl_cursor_theme == NULL) {
4657 RGFW_wl_cursor_theme = wl_cursor_theme_load(NULL, 24, shm);
4658 RGFW_cursor_surface = wl_compositor_create_surface(RGFW_compositor);
4659
4660 struct wl_cursor* cursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, "left_ptr");
4661 RGFW_cursor_image = cursor->images[0];
4662 struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(RGFW_cursor_image);
4663
4664 wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0);
4665 wl_surface_commit(RGFW_cursor_surface);
4666 }
4667
4668 if (RGFW_root == NULL)
4669 xdg_wm_base_add_listener(xdg_wm_base, &xdg_wm_base_listener, NULL);
4670
4671 xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
4672
4673 win->src.surface = wl_compositor_create_surface(RGFW_compositor);
4674 wl_surface_set_user_data(win->src.surface, win);
4675
4676 win->src.xdg_surface = xdg_wm_base_get_xdg_surface(xdg_wm_base, win->src.surface);
4677 xdg_surface_add_listener(win->src.xdg_surface, &xdg_surface_listener, NULL);
4678
4679 xdg_wm_base_set_user_data(xdg_wm_base, win);
4680
4681 win->src.xdg_toplevel = xdg_surface_get_toplevel(win->src.xdg_surface);
4682 xdg_toplevel_set_user_data(win->src.xdg_toplevel, win);
4683 xdg_toplevel_set_title(win->src.xdg_toplevel, name);
4684 xdg_toplevel_add_listener(win->src.xdg_toplevel, &xdg_toplevel_listener, NULL);
4685
4686 xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->r.w, win->r.h);
4687
4688 if (!(args & RGFW_NO_BORDER)) {
4689 win->src.decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
4690 decoration_manager, win->src.xdg_toplevel);
4691 }
4692
4693 if (args & RGFW_CENTER) {
4694 RGFW_area screenR = RGFW_getScreenSize();
4695 RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2));
4696 }
4697
4698 if (args & RGFW_OPENGL_SOFTWARE)
4699 setenv("LIBGL_ALWAYS_SOFTWARE", "1", 1);
4700
4701 wl_display_roundtrip(win->src.display);
4702
4703 wl_surface_commit(win->src.surface);
4704
4705 /* wait for the surface to be configured */
4706 while (wl_display_dispatch(win->src.display) != -1 && !RGFW_wl_configured) { }
4707
4708
4709 #ifdef RGFW_OPENGL
4710 if ((args & RGFW_NO_INIT_API) == 0) {
4711 win->src.window = wl_egl_window_create(win->src.surface, win->r.w, win->r.h);
4712 RGFW_createOpenGLContext(win);
4713 }
4714 #endif
4715
4716 RGFW_init_buffer(win);
4717
4718 struct wl_callback* callback = wl_surface_frame(win->src.surface);
4719 wl_callback_add_listener(callback, &wl_surface_frame_listener, win);
4720 wl_surface_commit(win->src.surface);
4721
4722 if (args & RGFW_HIDE_MOUSE) {
4723 RGFW_window_showMouse(win, 0);
4724 }
4725
4726 if (RGFW_root == NULL) {
4727 RGFW_root = win;
4728 }
4729
4730 win->src.eventIndex = 0;
4731 win->src.eventLen = 0;
4732
4733 return win;
4734 }
4735
4736 RGFW_Event* RGFW_window_checkEvent(RGFW_window* win) {
4737 if (win->_winArgs & RGFW_WINDOW_HIDE)
4738 return NULL;
4739
4740 if (win->src.eventIndex == 0) {
4741 if (wl_display_roundtrip(win->src.display) == -1) {
4742 return NULL;
4743 }
4744 RGFW_resetKey();
4745 }
4746
4747 #ifdef __linux__
4748 RGFW_Event* event = RGFW_linux_updateJoystick(win);
4749 if (event != NULL)
4750 return event;
4751 #endif
4752
4753 if (win->src.eventLen == 0) {
4754 return NULL;
4755 }
4756
4757 RGFW_Event ev = RGFW_eventPipe_pop(win);
4758
4759 if (ev.type == 0 || win->event.type == RGFW_quit) {
4760 return NULL;
4761 }
4762
4763 ev.frameTime = win->event.frameTime;
4764 ev.frameTime2 = win->event.frameTime2;
4765 ev.inFocus = win->event.inFocus;
4766 win->event = ev;
4767
4768 return &win->event;
4769 }
4770
4771
4772 void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
4773 RGFW_UNUSED(win); RGFW_UNUSED(a);
4774
4775 /* TODO wayland */
4776 }
4777
4778 void RGFW_window_move(RGFW_window* win, RGFW_point v) {
4779 RGFW_UNUSED(win); RGFW_UNUSED(v);
4780
4781 /* TODO wayland */
4782 }
4783
4784 void RGFW_window_setIcon(RGFW_window* win, u8* src, RGFW_area a, i32 channels) {
4785 RGFW_UNUSED(win); RGFW_UNUSED(src); RGFW_UNUSED(a); RGFW_UNUSED(channels)
4786 /* TODO wayland */
4787 }
4788
4789 void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) {
4790 RGFW_UNUSED(win); RGFW_UNUSED(v);
4791
4792 /* TODO wayland */
4793 }
4794
4795 void RGFW_window_showMouse(RGFW_window* win, i8 show) {
4796 RGFW_UNUSED(win);
4797
4798 if (show) {
4799
4800 }
4801 else {
4802
4803 }
4804
4805 /* TODO wayland */
4806 }
4807
4808 b8 RGFW_window_isMaximized(RGFW_window* win) {
4809 RGFW_UNUSED(win);
4810 /* TODO wayland */
4811 return 0;
4812 }
4813
4814 b8 RGFW_window_isMinimized(RGFW_window* win) {
4815 RGFW_UNUSED(win);
4816 /* TODO wayland */
4817 return 0;
4818 }
4819
4820 b8 RGFW_window_isHidden(RGFW_window* win) {
4821 RGFW_UNUSED(win);
4822 /* TODO wayland */
4823 return 0;
4824 }
4825
4826 b8 RGFW_window_isFullscreen(RGFW_window* win) {
4827 RGFW_UNUSED(win);
4828 /* TODO wayland */
4829 return 0;
4830 }
4831
4832 RGFW_point RGFW_window_getMousePoint(RGFW_window* win) {
4833 RGFW_UNUSED(win);
4834 /* TODO wayland */
4835 return RGFW_POINT(0, 0);
4836 }
4837
4838 RGFW_point RGFW_getGlobalMousePoint(void) {
4839 /* TODO wayland */
4840 return RGFW_POINT(0, 0);
4841 }
4842
4843 void RGFW_window_show(RGFW_window* win) {
4844 //wl_surface_attach(win->src.surface, win->rc., 0, 0);
4845 wl_surface_commit(win->src.surface);
4846
4847 if (win->_winArgs & RGFW_WINDOW_HIDE)
4848 win->_winArgs ^= RGFW_WINDOW_HIDE;
4849 }
4850
4851 void RGFW_window_hide(RGFW_window* win) {
4852 wl_surface_attach(win->src.surface, NULL, 0, 0);
4853 wl_surface_commit(win->src.surface);
4854 win->_winArgs |= RGFW_WINDOW_HIDE;
4855 }
4856
4857 void RGFW_window_setMouseDefault(RGFW_window* win) {
4858 RGFW_UNUSED(win);
4859
4860 RGFW_window_setMouseStandard(win, RGFW_MOUSE_NORMAL);
4861 }
4862
4863 void RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {
4864 RGFW_UNUSED(win);
4865
4866 static const char* iconStrings[] = { "left_ptr", "left_ptr", "text", "cross", "pointer", "e-resize", "n-resize", "nw-resize", "ne-resize", "all-resize", "not-allowed" };
4867
4868 struct wl_cursor* cursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, iconStrings[mouse]);
4869 RGFW_cursor_image = cursor->images[0];
4870 struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(RGFW_cursor_image);
4871
4872 wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0);
4873 wl_surface_commit(RGFW_cursor_surface);
4874 }
4875
4876 void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels) {
4877 RGFW_UNUSED(win); RGFW_UNUSED(image); RGFW_UNUSED(a); RGFW_UNUSED(channels)
4878 //struct wl_cursor* cursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, iconStrings[mouse]);
4879 //RGFW_cursor_image = image;
4880 struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(RGFW_cursor_image);
4881
4882 wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0);
4883 wl_surface_commit(RGFW_cursor_surface);
4884 }
4885
4886 void RGFW_window_setName(RGFW_window* win, char* name) {
4887 xdg_toplevel_set_title(win->src.xdg_toplevel, name);
4888 }
4889
4890 void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) {
4891 RGFW_UNUSED(win); RGFW_UNUSED(passthrough);
4892
4893 /* TODO wayland */
4894 }
4895
4896 void RGFW_window_setBorder(RGFW_window* win, b8 border) {
4897 RGFW_UNUSED(win); RGFW_UNUSED(border);
4898
4899 /* TODO wayland */
4900 }
4901
4902 void RGFW_window_restore(RGFW_window* win) {
4903 RGFW_UNUSED(win);
4904
4905 /* TODO wayland */
4906 }
4907
4908 void RGFW_window_minimize(RGFW_window* win) {
4909 RGFW_UNUSED(win);
4910
4911 /* TODO wayland */
4912 }
4913
4914 void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) {
4915 RGFW_UNUSED(win); RGFW_UNUSED(a);
4916
4917 /* TODO wayland */
4918 }
4919
4920 void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) {
4921 RGFW_UNUSED(win); RGFW_UNUSED(a);
4922
4923 /* TODO wayland */
4924 }
4925
4926 RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {
4927 RGFW_monitor m = {};
4928 RGFW_UNUSED(win);
4929 RGFW_UNUSED(m);
4930 /* TODO wayland */
4931
4932 return m;
4933 }
4934
4935
4936 #ifndef RGFW_EGL
4937 void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { RGFW_UNUSED(win); RGFW_UNUSED(swapInterval); }
4938 #endif
4939
4940 void RGFW_window_swapBuffers(RGFW_window* win) {
4941 assert(win != NULL);
4942
4943 /* clear the window*/
4944 #ifdef RGFW_BUFFER
4945 wl_surface_frame_done(win, NULL, 0);
4946 if (!(win->_winArgs & RGFW_NO_GPU_RENDER))
4947 #endif
4948 {
4949 #ifdef RGFW_OPENGL
4950 eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface);
4951 #endif
4952 }
4953
4954 wl_display_flush(win->src.display);
4955 }
4956
4957 void RGFW_window_close(RGFW_window* win) {
4958 #ifdef RGFW_EGL
4959 RGFW_closeEGL(win);
4960 #endif
4961
4962 if (RGFW_root == win) {
4963 RGFW_root = NULL;
4964 }
4965
4966 xdg_toplevel_destroy(win->src.xdg_toplevel);
4967 xdg_surface_destroy(win->src.xdg_surface);
4968 wl_surface_destroy(win->src.surface);
4969
4970 #ifdef RGFW_BUFFER
4971 wl_buffer_destroy(win->src.wl_buffer);
4972 #endif
4973
4974 wl_display_disconnect(win->src.display);
4975 RGFW_FREE(win);
4976 }
4977
4978 RGFW_monitor RGFW_getPrimaryMonitor(void) {
4979 /* TODO wayland */
4980
4981 return (RGFW_monitor){};
4982 }
4983
4984 RGFW_monitor* RGFW_getMonitors(void) {
4985 /* TODO wayland */
4986
4987 return NULL;
4988 }
4989
4990 void RGFW_writeClipboard(const char* text, u32 textLen) {
4991 RGFW_UNUSED(text); RGFW_UNUSED(textLen);
4992
4993 /* TODO wayland */
4994 }
4995
4996 char* RGFW_readClipboard(size_t* size) {
4997 RGFW_UNUSED(size);
4998
4999 /* TODO wayland */
5000
5001 return NULL;
5002 }
5003#endif /* RGFW_WAYLAND */
5004
5005/*
5006 End of Wayland defines
5007*/
5008
5009
5010/*
5011
5012 Start of Windows defines
5013
5014
5015*/
5016
5017#ifdef RGFW_WINDOWS
5018 #define WIN32_LEAN_AND_MEAN
5019 #define OEMRESOURCE
5020 #include <windows.h>
5021
5022 #include <processthreadsapi.h>
5023 #include <wchar.h>
5024 #include <locale.h>
5025 #include <windowsx.h>
5026 #include <shellapi.h>
5027 #include <shellscalingapi.h>
5028
5029 #include <winuser.h>
5030
5031 __declspec(dllimport) int __stdcall WideCharToMultiByte( UINT CodePage, DWORD dwFlags, const WCHAR* lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCCH lpDefaultChar, LPBOOL lpUsedDefaultChar);
5032
5033 #ifndef RGFW_NO_XINPUT
5034 typedef DWORD (WINAPI * PFN_XInputGetState)(DWORD,XINPUT_STATE*);
5035 PFN_XInputGetState XInputGetStateSRC = NULL;
5036 #define XInputGetState XInputGetStateSRC
5037
5038 typedef DWORD (WINAPI * PFN_XInputGetKeystroke)(DWORD, DWORD, PXINPUT_KEYSTROKE);
5039 PFN_XInputGetKeystroke XInputGetKeystrokeSRC = NULL;
5040 #define XInputGetKeystroke XInputGetKeystrokeSRC
5041
5042 static HMODULE RGFW_XInput_dll = NULL;
5043 #endif
5044
5045 u32 RGFW_mouseIconSrc[] = {OCR_NORMAL, OCR_NORMAL, OCR_IBEAM, OCR_CROSS, OCR_HAND, OCR_SIZEWE, OCR_SIZENS, OCR_SIZENWSE, OCR_SIZENESW, OCR_SIZEALL, OCR_NO};
5046
5047 char* createUTF8FromWideStringWin32(const WCHAR* source);
5048
5049#define GL_FRONT 0x0404
5050#define GL_BACK 0x0405
5051#define GL_LEFT 0x0406
5052#define GL_RIGHT 0x0407
5053
5054#if defined(RGFW_OSMESA) && defined(RGFW_LINK_OSMESA)
5055
5056 typedef void (GLAPIENTRY* PFN_OSMesaDestroyContext)(OSMesaContext);
5057 typedef i32(GLAPIENTRY* PFN_OSMesaMakeCurrent)(OSMesaContext, void*, int, int, int);
5058 typedef OSMesaContext(GLAPIENTRY* PFN_OSMesaCreateContext)(GLenum, OSMesaContext);
5059
5060 PFN_OSMesaMakeCurrent OSMesaMakeCurrentSource;
5061 PFN_OSMesaCreateContext OSMesaCreateContextSource;
5062 PFN_OSMesaDestroyContext OSMesaDestroyContextSource;
5063
5064#define OSMesaCreateContext OSMesaCreateContextSource
5065#define OSMesaMakeCurrent OSMesaMakeCurrentSource
5066#define OSMesaDestroyContext OSMesaDestroyContextSource
5067#endif
5068
5069 typedef int (*PFN_wglGetSwapIntervalEXT)(void);
5070 PFN_wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc = NULL;
5071#define wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc
5072
5073
5074 void* RGFWjoystickApi = NULL;
5075
5076 /* these two wgl functions need to be preloaded */
5077 typedef HGLRC (WINAPI *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hdc, HGLRC hglrc, const int *attribList);
5078 PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;
5079
5080 /* defines for creating ARB attributes */
5081#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
5082#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
5083#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
5084#define WGL_DRAW_TO_WINDOW_ARB 0x2001
5085#define WGL_ACCELERATION_ARB 0x2003
5086#define WGL_NO_ACCELERATION_ARB 0x2025
5087#define WGL_DOUBLE_BUFFER_ARB 0x2011
5088#define WGL_COLOR_BITS_ARB 0x2014
5089#define WGL_RED_BITS_ARB 0x2015
5090#define WGL_RED_SHIFT_ARB 0x2016
5091#define WGL_GREEN_BITS_ARB 0x2017
5092#define WGL_GREEN_SHIFT_ARB 0x2018
5093#define WGL_BLUE_BITS_ARB 0x2019
5094#define WGL_BLUE_SHIFT_ARB 0x201a
5095#define WGL_ALPHA_BITS_ARB 0x201b
5096#define WGL_ALPHA_SHIFT_ARB 0x201c
5097#define WGL_ACCUM_BITS_ARB 0x201d
5098#define WGL_ACCUM_RED_BITS_ARB 0x201e
5099#define WGL_ACCUM_GREEN_BITS_ARB 0x201f
5100#define WGL_ACCUM_BLUE_BITS_ARB 0x2020
5101#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
5102#define WGL_DEPTH_BITS_ARB 0x2022
5103#define WGL_AUX_BUFFERS_ARB 0x2024
5104#define WGL_STEREO_ARB 0x2012
5105#define WGL_DEPTH_BITS_ARB 0x2022
5106#define WGL_STENCIL_BITS_ARB 0x2023
5107#define WGL_FULL_ACCELERATION_ARB 0x2027
5108#define WGL_CONTEXT_FLAGS_ARB 0x2094
5109#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
5110#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
5111#define WGL_SAMPLE_BUFFERS_ARB 0x2041
5112#define WGL_SAMPLES_ARB 0x2042
5113#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9
5114
5115#ifndef RGFW_EGL
5116static HMODULE wglinstance = NULL;
5117#endif
5118
5119#ifdef RGFW_WGL_LOAD
5120 typedef HGLRC(WINAPI* PFN_wglCreateContext)(HDC);
5121 typedef BOOL(WINAPI* PFN_wglDeleteContext)(HGLRC);
5122 typedef PROC(WINAPI* PFN_wglGetProcAddress)(LPCSTR);
5123 typedef BOOL(WINAPI* PFN_wglMakeCurrent)(HDC, HGLRC);
5124 typedef HDC(WINAPI* PFN_wglGetCurrentDC)();
5125 typedef HGLRC(WINAPI* PFN_wglGetCurrentContext)();
5126
5127 PFN_wglCreateContext wglCreateContextSRC;
5128 PFN_wglDeleteContext wglDeleteContextSRC;
5129 PFN_wglGetProcAddress wglGetProcAddressSRC;
5130 PFN_wglMakeCurrent wglMakeCurrentSRC;
5131 PFN_wglGetCurrentDC wglGetCurrentDCSRC;
5132 PFN_wglGetCurrentContext wglGetCurrentContextSRC;
5133
5134 #define wglCreateContext wglCreateContextSRC
5135 #define wglDeleteContext wglDeleteContextSRC
5136 #define wglGetProcAddress wglGetProcAddressSRC
5137 #define wglMakeCurrent wglMakeCurrentSRC
5138
5139 #define wglGetCurrentDC wglGetCurrentDCSRC
5140 #define wglGetCurrentContext wglGetCurrentContextSRC
5141#endif
5142
5143#ifdef RGFW_OPENGL
5144 void* RGFW_getProcAddress(const char* procname) {
5145 void* proc = (void*) wglGetProcAddress(procname);
5146 if (proc)
5147 return proc;
5148
5149 return (void*) GetProcAddress(wglinstance, procname);
5150 }
5151
5152 typedef HRESULT (APIENTRY* PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats);
5153 static PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL;
5154#endif
5155
5156 RGFW_window RGFW_eventWindow;
5157
5158 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
5159 switch (message) {
5160 case WM_MOVE:
5161 RGFW_eventWindow.r.x = LOWORD(lParam);
5162 RGFW_eventWindow.r.y = HIWORD(lParam);
5163 RGFW_eventWindow.src.window = hWnd;
5164 return DefWindowProcA(hWnd, message, wParam, lParam);
5165 case WM_SIZE:
5166 RGFW_eventWindow.r.w = LOWORD(lParam);
5167 RGFW_eventWindow.r.h = HIWORD(lParam);
5168 RGFW_eventWindow.src.window = hWnd;
5169 return DefWindowProcA(hWnd, message, wParam, lParam); // Call DefWindowProc after handling
5170 default:
5171 return DefWindowProcA(hWnd, message, wParam, lParam);
5172 }
5173 }
5174
5175 #ifndef RGFW_NO_DPI
5176 static HMODULE RGFW_Shcore_dll = NULL;
5177 typedef HRESULT (WINAPI * PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,UINT*);
5178 PFN_GetDpiForMonitor GetDpiForMonitorSRC = NULL;
5179 #define GetDpiForMonitor GetDpiForMonitorSRC
5180 #endif
5181
5182 __declspec(dllimport) u32 __stdcall timeBeginPeriod(u32 uPeriod);
5183
5184 #ifndef RGFW_NO_XINPUT
5185 void RGFW_loadXInput(void) {
5186 u32 i;
5187 static const char* names[] = {
5188 "xinput1_4.dll",
5189 "xinput1_3.dll",
5190 "xinput9_1_0.dll",
5191 "xinput1_2.dll",
5192 "xinput1_1.dll"
5193 };
5194
5195 for (i = 0; i < sizeof(names) / sizeof(const char*); i++) {
5196 RGFW_XInput_dll = LoadLibraryA(names[i]);
5197
5198 if (RGFW_XInput_dll) {
5199 XInputGetStateSRC = (PFN_XInputGetState)(void*)GetProcAddress(RGFW_XInput_dll, "XInputGetState");
5200
5201 if (XInputGetStateSRC == NULL)
5202 printf("Failed to load XInputGetState");
5203 }
5204 }
5205 }
5206 #endif
5207
5208 RGFWDEF void RGFW_init_buffer(RGFW_window* win);
5209 void RGFW_init_buffer(RGFW_window* win) {
5210#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
5211 if (RGFW_bufferSize.w == 0 && RGFW_bufferSize.h == 0)
5212 RGFW_bufferSize = RGFW_getScreenSize();
5213
5214 BITMAPV5HEADER bi = { 0 };
5215 ZeroMemory(&bi, sizeof(bi));
5216 bi.bV5Size = sizeof(bi);
5217 bi.bV5Width = RGFW_bufferSize.w;
5218 bi.bV5Height = -((LONG) RGFW_bufferSize.h);
5219 bi.bV5Planes = 1;
5220 bi.bV5BitCount = 32;
5221 bi.bV5Compression = BI_BITFIELDS;
5222 bi.bV5BlueMask = 0x00ff0000;
5223 bi.bV5GreenMask = 0x0000ff00;
5224 bi.bV5RedMask = 0x000000ff;
5225 bi.bV5AlphaMask = 0xff000000;
5226
5227 win->src.bitmap = CreateDIBSection(win->src.hdc,
5228 (BITMAPINFO*) &bi,
5229 DIB_RGB_COLORS,
5230 (void**) &win->buffer,
5231 NULL,
5232 (DWORD) 0);
5233
5234 win->src.hdcMem = CreateCompatibleDC(win->src.hdc);
5235
5236 #if defined(RGFW_OSMESA)
5237 win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL);
5238 OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, win->r.w, win->r.h);
5239 #endif
5240#else
5241RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
5242#endif
5243 }
5244
5245 void RGFW_window_setDND(RGFW_window* win, b8 allow) {
5246 DragAcceptFiles(win->src.window, allow);
5247 }
5248
5249 void RGFW_releaseCursor(RGFW_window* win) {
5250 RGFW_UNUSED(win);
5251 ClipCursor(NULL);
5252 const RAWINPUTDEVICE id = { 0x01, 0x02, RIDEV_REMOVE, NULL };
5253 RegisterRawInputDevices(&id, 1, sizeof(id));
5254 }
5255
5256 void RGFW_captureCursor(RGFW_window* win, RGFW_rect rect) {
5257 RGFW_UNUSED(win); RGFW_UNUSED(rect);
5258
5259 RECT clipRect;
5260 GetClientRect(win->src.window, &clipRect);
5261 ClientToScreen(win->src.window, (POINT*) &clipRect.left);
5262 ClientToScreen(win->src.window, (POINT*) &clipRect.right);
5263 ClipCursor(&clipRect);
5264
5265 const RAWINPUTDEVICE id = { 0x01, 0x02, 0, win->src.window };
5266 RegisterRawInputDevices(&id, 1, sizeof(id));
5267 }
5268
5269 RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) {
5270 #ifndef RGFW_NO_XINPUT
5271 if (RGFW_XInput_dll == NULL)
5272 RGFW_loadXInput();
5273 #endif
5274
5275 #ifndef RGFW_NO_DPI
5276 if (RGFW_Shcore_dll == NULL) {
5277 RGFW_Shcore_dll = LoadLibraryA("shcore.dll");
5278 GetDpiForMonitorSRC = (PFN_GetDpiForMonitor)(void*)GetProcAddress(RGFW_Shcore_dll, "GetDpiForMonitor");
5279 SetProcessDPIAware();
5280 }
5281 #endif
5282
5283 if (wglinstance == NULL) {
5284 wglinstance = LoadLibraryA("opengl32.dll");
5285#ifdef RGFW_WGL_LOAD
5286 wglCreateContextSRC = (PFN_wglCreateContext) GetProcAddress(wglinstance, "wglCreateContext");
5287 wglDeleteContextSRC = (PFN_wglDeleteContext) GetProcAddress(wglinstance, "wglDeleteContext");
5288 wglGetProcAddressSRC = (PFN_wglGetProcAddress) GetProcAddress(wglinstance, "wglGetProcAddress");
5289 wglMakeCurrentSRC = (PFN_wglMakeCurrent) GetProcAddress(wglinstance, "wglMakeCurrent");
5290 wglGetCurrentDCSRC = (PFN_wglGetCurrentDC) GetProcAddress(wglinstance, "wglGetCurrentDC");
5291 wglGetCurrentContextSRC = (PFN_wglGetCurrentContext) GetProcAddress(wglinstance, "wglGetCurrentContext");
5292#endif
5293 }
5294
5295 if (name[0] == 0) name = (char*) " ";
5296
5297 RGFW_eventWindow.r = RGFW_RECT(-1, -1, -1, -1);
5298 RGFW_eventWindow.src.window = NULL;
5299
5300 RGFW_window* win = RGFW_window_basic_init(rect, args);
5301
5302 win->src.maxSize = RGFW_AREA(0, 0);
5303 win->src.minSize = RGFW_AREA(0, 0);
5304
5305
5306 HINSTANCE inh = GetModuleHandleA(NULL);
5307
5308 #ifndef __cplusplus
5309 WNDCLASSA Class = { 0 }; /*!< Setup the Window class. */
5310 #else
5311 WNDCLASSA Class = { };
5312 #endif
5313
5314 if (RGFW_className == NULL)
5315 RGFW_className = (char*)name;
5316
5317 Class.lpszClassName = RGFW_className;
5318 Class.hInstance = inh;
5319 Class.hCursor = LoadCursor(NULL, IDC_ARROW);
5320 Class.lpfnWndProc = WndProc;
5321
5322 RegisterClassA(&Class);
5323
5324 DWORD window_style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
5325
5326 RECT windowRect, clientRect;
5327
5328 if (!(args & RGFW_NO_BORDER)) {
5329 window_style |= WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX;
5330
5331 if (!(args & RGFW_NO_RESIZE))
5332 window_style |= WS_SIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME;
5333 } else
5334 window_style |= WS_POPUP | WS_VISIBLE | WS_SYSMENU | WS_MINIMIZEBOX;
5335
5336 HWND dummyWin = CreateWindowA(Class.lpszClassName, name, window_style, win->r.x, win->r.y, win->r.w, win->r.h, 0, 0, inh, 0);
5337
5338 GetWindowRect(dummyWin, &windowRect);
5339 GetClientRect(dummyWin, &clientRect);
5340
5341 win->src.hOffset = (windowRect.bottom - windowRect.top) - (clientRect.bottom - clientRect.top);
5342 win->src.window = CreateWindowA(Class.lpszClassName, name, window_style, win->r.x, win->r.y, win->r.w, win->r.h + win->src.hOffset, 0, 0, inh, 0);
5343
5344 if (args & RGFW_ALLOW_DND) {
5345 win->_winArgs |= RGFW_ALLOW_DND;
5346 RGFW_window_setDND(win, 1);
5347 }
5348 win->src.hdc = GetDC(win->src.window);
5349
5350 if ((args & RGFW_NO_INIT_API) == 0) {
5351#ifdef RGFW_DIRECTX
5352 assert(FAILED(CreateDXGIFactory(&__uuidof(IDXGIFactory), (void**) &RGFW_dxInfo.pFactory)) == 0);
5353
5354 if (FAILED(RGFW_dxInfo.pFactory->lpVtbl->EnumAdapters(RGFW_dxInfo.pFactory, 0, &RGFW_dxInfo.pAdapter))) {
5355 fprintf(stderr, "Failed to enumerate DXGI adapters\n");
5356 RGFW_dxInfo.pFactory->lpVtbl->Release(RGFW_dxInfo.pFactory);
5357 return NULL;
5358 }
5359
5360 D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0 };
5361
5362 if (FAILED(D3D11CreateDevice(RGFW_dxInfo.pAdapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, 0, featureLevels, 1, D3D11_SDK_VERSION, &RGFW_dxInfo.pDevice, NULL, &RGFW_dxInfo.pDeviceContext))) {
5363 fprintf(stderr, "Failed to create Direct3D device\n");
5364 RGFW_dxInfo.pAdapter->lpVtbl->Release(RGFW_dxInfo.pAdapter);
5365 RGFW_dxInfo.pFactory->lpVtbl->Release(RGFW_dxInfo.pFactory);
5366 return NULL;
5367 }
5368
5369 DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 };
5370 swapChainDesc.BufferCount = 1;
5371 swapChainDesc.BufferDesc.Width = win->r.w;
5372 swapChainDesc.BufferDesc.Height = win->r.h;
5373 swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
5374 swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
5375 swapChainDesc.OutputWindow = win->src.window;
5376 swapChainDesc.SampleDesc.Count = 1;
5377 swapChainDesc.SampleDesc.Quality = 0;
5378 swapChainDesc.Windowed = TRUE;
5379 RGFW_dxInfo.pFactory->lpVtbl->CreateSwapChain(RGFW_dxInfo.pFactory, (IUnknown*) RGFW_dxInfo.pDevice, &swapChainDesc, &win->src.swapchain);
5380
5381 ID3D11Texture2D* pBackBuffer;
5382 win->src.swapchain->lpVtbl->GetBuffer(win->src.swapchain, 0, &__uuidof(ID3D11Texture2D), (LPVOID*) &pBackBuffer);
5383 RGFW_dxInfo.pDevice->lpVtbl->CreateRenderTargetView(RGFW_dxInfo.pDevice, (ID3D11Resource*) pBackBuffer, NULL, &win->src.renderTargetView);
5384 pBackBuffer->lpVtbl->Release(pBackBuffer);
5385
5386 D3D11_TEXTURE2D_DESC depthStencilDesc = { 0 };
5387 depthStencilDesc.Width = win->r.w;
5388 depthStencilDesc.Height = win->r.h;
5389 depthStencilDesc.MipLevels = 1;
5390 depthStencilDesc.ArraySize = 1;
5391 depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
5392 depthStencilDesc.SampleDesc.Count = 1;
5393 depthStencilDesc.SampleDesc.Quality = 0;
5394 depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
5395 depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
5396
5397 ID3D11Texture2D* pDepthStencilTexture = NULL;
5398 RGFW_dxInfo.pDevice->lpVtbl->CreateTexture2D(RGFW_dxInfo.pDevice, &depthStencilDesc, NULL, &pDepthStencilTexture);
5399
5400 D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc = { 0 };
5401 depthStencilViewDesc.Format = depthStencilDesc.Format;
5402 depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
5403 depthStencilViewDesc.Texture2D.MipSlice = 0;
5404
5405 RGFW_dxInfo.pDevice->lpVtbl->CreateDepthStencilView(RGFW_dxInfo.pDevice, (ID3D11Resource*) pDepthStencilTexture, &depthStencilViewDesc, &win->src.pDepthStencilView);
5406
5407 pDepthStencilTexture->lpVtbl->Release(pDepthStencilTexture);
5408
5409 RGFW_dxInfo.pDeviceContext->lpVtbl->OMSetRenderTargets(RGFW_dxInfo.pDeviceContext, 1, &win->src.renderTargetView, win->src.pDepthStencilView);
5410#endif
5411
5412#ifdef RGFW_OPENGL
5413 HDC dummy_dc = GetDC(dummyWin);
5414
5415 u32 pfd_flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
5416
5417 //if (RGFW_DOUBLE_BUFFER)
5418 pfd_flags |= PFD_DOUBLEBUFFER;
5419
5420 PIXELFORMATDESCRIPTOR pfd = {
5421 sizeof(pfd),
5422 1, /* version */
5423 pfd_flags,
5424 PFD_TYPE_RGBA, /* ipixel type */
5425 24, /* color bits */
5426 0, 0, 0, 0, 0, 0,
5427 8, /* alpha bits */
5428 0, 0, 0, 0, 0, 0,
5429 32, /* depth bits */
5430 8, /* stencil bits */
5431 0,
5432 PFD_MAIN_PLANE, /* Layer type */
5433 0, 0, 0, 0
5434 };
5435
5436 int pixel_format = ChoosePixelFormat(dummy_dc, &pfd);
5437 SetPixelFormat(dummy_dc, pixel_format, &pfd);
5438
5439 HGLRC dummy_context = wglCreateContext(dummy_dc);
5440 wglMakeCurrent(dummy_dc, dummy_context);
5441
5442 if (wglChoosePixelFormatARB == NULL) {
5443 wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) (void*) wglGetProcAddress("wglCreateContextAttribsARB");
5444 wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC) (void*)wglGetProcAddress("wglChoosePixelFormatARB");
5445 }
5446
5447 wglMakeCurrent(dummy_dc, 0);
5448 wglDeleteContext(dummy_context);
5449 ReleaseDC(dummyWin, dummy_dc);
5450
5451 /* try to create the pixel format we want for opengl and then try to create an opengl context for the specified version */
5452 if (wglCreateContextAttribsARB != NULL) {
5453 PIXELFORMATDESCRIPTOR pfd = {sizeof(pfd), 1, pfd_flags, PFD_TYPE_RGBA, 32, 8, PFD_MAIN_PLANE, 24, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
5454
5455 if (args & RGFW_OPENGL_SOFTWARE)
5456 pfd.dwFlags |= PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED;
5457
5458 if (wglChoosePixelFormatARB != NULL) {
5459 i32* pixel_format_attribs = (i32*)RGFW_initFormatAttribs(args & RGFW_OPENGL_SOFTWARE);
5460
5461 int pixel_format;
5462 UINT num_formats;
5463 wglChoosePixelFormatARB(win->src.hdc, pixel_format_attribs, 0, 1, &pixel_format, &num_formats);
5464 if (!num_formats) {
5465 printf("Failed to create a pixel format for WGL.\n");
5466 }
5467
5468 DescribePixelFormat(win->src.hdc, pixel_format, sizeof(pfd), &pfd);
5469 if (!SetPixelFormat(win->src.hdc, pixel_format, &pfd)) {
5470 printf("Failed to set the WGL pixel format.\n");
5471 }
5472 }
5473
5474 /* create opengl/WGL context for the specified version */
5475 u32 index = 0;
5476 i32 attribs[40];
5477
5478 if (RGFW_profile == RGFW_GL_CORE) {
5479 SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB);
5480 }
5481 else {
5482 SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB);
5483 }
5484
5485 if (RGFW_majorVersion || RGFW_minorVersion) {
5486 SET_ATTRIB(WGL_CONTEXT_MAJOR_VERSION_ARB, RGFW_majorVersion);
5487 SET_ATTRIB(WGL_CONTEXT_MINOR_VERSION_ARB, RGFW_minorVersion);
5488 }
5489
5490 SET_ATTRIB(0, 0);
5491
5492 win->src.ctx = (HGLRC)wglCreateContextAttribsARB(win->src.hdc, NULL, attribs);
5493 } else { /* fall back to a default context (probably opengl 2 or something) */
5494 fprintf(stderr, "Failed to create an accelerated OpenGL Context\n");
5495
5496 int pixel_format = ChoosePixelFormat(win->src.hdc, &pfd);
5497 SetPixelFormat(win->src.hdc, pixel_format, &pfd);
5498
5499 win->src.ctx = wglCreateContext(win->src.hdc);
5500 }
5501
5502 wglMakeCurrent(win->src.hdc, win->src.ctx);
5503#endif
5504 }
5505
5506#ifdef RGFW_OSMESA
5507#ifdef RGFW_LINK_OSM ESA
5508 OSMesaMakeCurrentSource = (PFN_OSMesaMakeCurrent) GetProcAddress(win->src.hdc, "OSMesaMakeCurrent");
5509 OSMesaCreateContextSource = (PFN_OSMesaCreateContext) GetProcAddress(win->src.hdc, "OSMesaCreateContext");
5510 OSMesaDestroyContextSource = (PFN_OSMesaDestroyContext) GetProcAddress(win->src.hdc, "OSMesaDestroyContext");
5511#endif
5512#endif
5513
5514#ifdef RGFW_OPENGL
5515 if ((args & RGFW_NO_INIT_API) == 0) {
5516 ReleaseDC(win->src.window, win->src.hdc);
5517 win->src.hdc = GetDC(win->src.window);
5518 wglMakeCurrent(win->src.hdc, win->src.ctx);
5519 }
5520#endif
5521
5522 DestroyWindow(dummyWin);
5523 RGFW_init_buffer(win);
5524
5525
5526 #ifndef RGFW_NO_MONITOR
5527 if (args & RGFW_SCALE_TO_MONITOR)
5528 RGFW_window_scaleToMonitor(win);
5529 #endif
5530
5531 if (args & RGFW_CENTER) {
5532 RGFW_area screenR = RGFW_getScreenSize();
5533 RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2));
5534 }
5535
5536#ifdef RGFW_EGL
5537 if ((args & RGFW_NO_INIT_API) == 0)
5538 RGFW_createOpenGLContext(win);
5539#endif
5540
5541 if (args & RGFW_HIDE_MOUSE)
5542 RGFW_window_showMouse(win, 0);
5543
5544 if (args & RGFW_TRANSPARENT_WINDOW) {
5545 SetWindowLong(win->src.window, GWL_EXSTYLE, GetWindowLong(win->src.window, GWL_EXSTYLE) | WS_EX_LAYERED);
5546 SetLayeredWindowAttributes(win->src.window, RGB(255, 255, 255), RGFW_ALPHA, LWA_ALPHA);
5547 }
5548
5549 ShowWindow(win->src.window, SW_SHOWNORMAL);
5550
5551 if (RGFW_root == NULL)
5552 RGFW_root = win;
5553
5554 #ifdef RGFW_OPENGL
5555 else
5556 wglShareLists(RGFW_root->src.ctx, win->src.ctx);
5557 #endif
5558
5559 return win;
5560 }
5561
5562 void RGFW_window_setBorder(RGFW_window* win, u8 border) {
5563 DWORD style = GetWindowLong(win->src.window, GWL_STYLE);
5564
5565 if (border == 0) {
5566 SetWindowLong(win->src.window, GWL_STYLE, style & ~WS_OVERLAPPEDWINDOW);
5567 SetWindowPos(
5568 win->src.window, HWND_TOP, 0, 0, 0, 0,
5569 SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE
5570 );
5571 }
5572 else {
5573 SetWindowLong(win->src.window, GWL_STYLE, style | WS_OVERLAPPEDWINDOW);
5574 SetWindowPos(
5575 win->src.window, HWND_TOP, 0, 0, 0, 0,
5576 SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE
5577 );
5578 }
5579 }
5580
5581
5582 RGFW_area RGFW_getScreenSize(void) {
5583 return RGFW_AREA(GetDeviceCaps(GetDC(NULL), HORZRES), GetDeviceCaps(GetDC(NULL), VERTRES));
5584 }
5585
5586 RGFW_point RGFW_getGlobalMousePoint(void) {
5587 POINT p;
5588 GetCursorPos(&p);
5589
5590 return RGFW_POINT(p.x, p.y);
5591 }
5592
5593 RGFW_point RGFW_window_getMousePoint(RGFW_window* win) {
5594 POINT p;
5595 GetCursorPos(&p);
5596 ScreenToClient(win->src.window, &p);
5597
5598 return RGFW_POINT(p.x, p.y);
5599 }
5600
5601 void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) {
5602 assert(win != NULL);
5603 win->src.minSize = a;
5604 }
5605
5606 void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) {
5607 assert(win != NULL);
5608 win->src.maxSize = a;
5609 }
5610
5611
5612 void RGFW_window_minimize(RGFW_window* win) {
5613 assert(win != NULL);
5614
5615 ShowWindow(win->src.window, SW_MINIMIZE);
5616 }
5617
5618 void RGFW_window_restore(RGFW_window* win) {
5619 assert(win != NULL);
5620
5621 ShowWindow(win->src.window, SW_RESTORE);
5622 }
5623
5624
5625 u8 RGFW_xinput2RGFW[] = {
5626 RGFW_JS_A, /* or PS X button */
5627 RGFW_JS_B, /* or PS circle button */
5628 RGFW_JS_X, /* or PS square button */
5629 RGFW_JS_Y, /* or PS triangle button */
5630 RGFW_JS_R1, /* right bumper */
5631 RGFW_JS_L1, /* left bump */
5632 RGFW_JS_L2, /* left trigger*/
5633 RGFW_JS_R2, /* right trigger */
5634 0, 0, 0, 0, 0, 0, 0, 0,
5635 RGFW_JS_UP, /* dpad up */
5636 RGFW_JS_DOWN, /* dpad down*/
5637 RGFW_JS_LEFT, /* dpad left */
5638 RGFW_JS_RIGHT, /* dpad right */
5639 RGFW_JS_START, /* start button */
5640 RGFW_JS_SELECT/* select button */
5641 };
5642
5643 static i32 RGFW_checkXInput(RGFW_window* win, RGFW_Event* e) {
5644 RGFW_UNUSED(win)
5645
5646 size_t i;
5647 for (i = 0; i < 4; i++) {
5648 XINPUT_KEYSTROKE keystroke;
5649
5650 if (XInputGetKeystroke == NULL)
5651 return 0;
5652
5653 DWORD result = XInputGetKeystroke((DWORD)i, 0, &keystroke);
5654
5655 if ((keystroke.Flags & XINPUT_KEYSTROKE_REPEAT) == 0 && result != ERROR_EMPTY) {
5656 if (result != ERROR_SUCCESS)
5657 return 0;
5658
5659 if (keystroke.VirtualKey > VK_PAD_BACK)
5660 continue;
5661
5662 // RGFW_jsButtonPressed + 1 = RGFW_jsButtonReleased
5663 e->type = RGFW_jsButtonPressed + !(keystroke.Flags & XINPUT_KEYSTROKE_KEYDOWN);
5664 e->button = RGFW_xinput2RGFW[keystroke.VirtualKey - 0x5800];
5665 RGFW_jsPressed[i][e->button] = !(keystroke.Flags & XINPUT_KEYSTROKE_KEYDOWN);
5666
5667 return 1;
5668 }
5669
5670 XINPUT_STATE state;
5671 if (XInputGetState == NULL ||
5672 XInputGetState((DWORD) i, &state) == ERROR_DEVICE_NOT_CONNECTED
5673 )
5674 return 0;
5675#define INPUT_DEADZONE ( 0.24f * (float)(0x7FFF) ) // Default to 24% of the +/- 32767 range. This is a reasonable default value but can be altered if needed.
5676
5677 if ((state.Gamepad.sThumbLX < INPUT_DEADZONE &&
5678 state.Gamepad.sThumbLX > -INPUT_DEADZONE) &&
5679 (state.Gamepad.sThumbLY < INPUT_DEADZONE &&
5680 state.Gamepad.sThumbLY > -INPUT_DEADZONE))
5681 {
5682 state.Gamepad.sThumbLX = 0;
5683 state.Gamepad.sThumbLY = 0;
5684 }
5685
5686 if ((state.Gamepad.sThumbRX < INPUT_DEADZONE &&
5687 state.Gamepad.sThumbRX > -INPUT_DEADZONE) &&
5688 (state.Gamepad.sThumbRY < INPUT_DEADZONE &&
5689 state.Gamepad.sThumbRY > -INPUT_DEADZONE))
5690 {
5691 state.Gamepad.sThumbRX = 0;
5692 state.Gamepad.sThumbRY = 0;
5693 }
5694
5695 e->axisesCount = 2;
5696 RGFW_point axis1 = RGFW_POINT(state.Gamepad.sThumbLX, state.Gamepad.sThumbLY);
5697 RGFW_point axis2 = RGFW_POINT(state.Gamepad.sThumbRX, state.Gamepad.sThumbRY);
5698
5699 if (axis1.x != e->axis[0].x || axis1.y != e->axis[0].y || axis2.x != e->axis[1].x || axis2.y != e->axis[1].y) {
5700 e->type = RGFW_jsAxisMove;
5701
5702 e->axis[0] = axis1;
5703 e->axis[1] = axis2;
5704
5705 return 1;
5706 }
5707
5708 e->axis[0] = axis1;
5709 e->axis[1] = axis2;
5710 }
5711
5712 return 0;
5713 }
5714
5715 void RGFW_stopCheckEvents(void) {
5716 PostMessageW(RGFW_root->src.window, WM_NULL, 0, 0);
5717 }
5718
5719 void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) {
5720 RGFW_UNUSED(win);
5721
5722 MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD) (waitMS * 1e3), QS_ALLINPUT);
5723 }
5724
5725 RGFW_Event* RGFW_window_checkEvent(RGFW_window* win) {
5726 assert(win != NULL);
5727
5728 if (win->event.type == RGFW_quit) {
5729 return NULL;
5730 }
5731
5732 MSG msg;
5733
5734 if (RGFW_eventWindow.src.window == win->src.window) {
5735 if (RGFW_eventWindow.r.x != -1) {
5736 win->r.x = RGFW_eventWindow.r.x;
5737 win->r.y = RGFW_eventWindow.r.y;
5738 win->event.type = RGFW_windowMoved;
5739 RGFW_windowMoveCallback(win, win->r);
5740 }
5741
5742 if (RGFW_eventWindow.r.w != -1) {
5743 win->r.w = RGFW_eventWindow.r.w;
5744 win->r.h = RGFW_eventWindow.r.h;
5745 win->event.type = RGFW_windowResized;
5746 RGFW_windowResizeCallback(win, win->r);
5747 }
5748
5749 RGFW_eventWindow.src.window = NULL;
5750 RGFW_eventWindow.r = RGFW_RECT(-1, -1, -1, -1);
5751
5752 return &win->event;
5753 }
5754
5755
5756 static HDROP drop;
5757
5758 if (win->event.type == RGFW_dnd_init) {
5759 if (win->event.droppedFilesCount) {
5760 u32 i;
5761 for (i = 0; i < win->event.droppedFilesCount; i++)
5762 win->event.droppedFiles[i][0] = '\0';
5763 }
5764
5765 win->event.droppedFilesCount = 0;
5766 win->event.droppedFilesCount = DragQueryFileW(drop, 0xffffffff, NULL, 0);
5767 //win->event.droppedFiles = (char**)RGFW_CALLOC(win->event.droppedFilesCount, sizeof(char*));
5768
5769 u32 i;
5770 for (i = 0; i < win->event.droppedFilesCount; i++) {
5771 const UINT length = DragQueryFileW(drop, i, NULL, 0);
5772 WCHAR* buffer = (WCHAR*) RGFW_CALLOC((size_t) length + 1, sizeof(WCHAR));
5773
5774 DragQueryFileW(drop, i, buffer, length + 1);
5775 strncpy(win->event.droppedFiles[i], createUTF8FromWideStringWin32(buffer), RGFW_MAX_PATH);
5776 win->event.droppedFiles[i][RGFW_MAX_PATH - 1] = '\0';
5777 RGFW_FREE(buffer);
5778 }
5779
5780 DragFinish(drop);
5781 RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount);
5782
5783 win->event.type = RGFW_dnd;
5784 return &win->event;
5785 }
5786
5787 win->event.inFocus = (GetForegroundWindow() == win->src.window);
5788
5789 if (RGFW_checkXInput(win, &win->event))
5790 return &win->event;
5791
5792 static BYTE keyboardState[256];
5793
5794 if (PeekMessageA(&msg, win->src.window, 0u, 0u, PM_REMOVE)) {
5795 switch (msg.message) {
5796 case WM_CLOSE:
5797 case WM_QUIT:
5798 RGFW_windowQuitCallback(win);
5799 win->event.type = RGFW_quit;
5800 break;
5801
5802 case WM_ACTIVATE:
5803 win->event.inFocus = (LOWORD(msg.wParam) == WA_INACTIVE);
5804
5805 if (win->event.inFocus) {
5806 win->event.type = RGFW_focusIn;
5807 RGFW_focusCallback(win, 1);
5808 }
5809 else {
5810 win->event.type = RGFW_focusOut;
5811 RGFW_focusCallback(win, 0);
5812 }
5813
5814 break;
5815
5816 case WM_PAINT:
5817 win->event.type = RGFW_windowRefresh;
5818 RGFW_windowRefreshCallback(win);
5819 break;
5820
5821 case WM_MOUSELEAVE:
5822 win->event.type = RGFW_mouseLeave;
5823 win->_winArgs |= RGFW_MOUSE_LEFT;
5824 RGFW_mouseNotifyCallBack(win, win->event.point, 0);
5825 break;
5826
5827 case WM_KEYUP: {
5828 win->event.keyCode = RGFW_apiKeyCodeToRGFW((u32) msg.wParam);
5829
5830 RGFW_keyboard[win->event.keyCode].prev = RGFW_isPressed(win, win->event.keyCode);
5831
5832 static char keyName[16];
5833
5834 {
5835 GetKeyNameTextA((LONG) msg.lParam, keyName, 16);
5836
5837 if ((!(GetKeyState(VK_CAPITAL) & 0x0001) && !(GetKeyState(VK_SHIFT) & 0x8000)) ||
5838 ((GetKeyState(VK_CAPITAL) & 0x0001) && (GetKeyState(VK_SHIFT) & 0x8000))) {
5839 CharLowerBuffA(keyName, 16);
5840 }
5841 }
5842
5843 RGFW_updateLockState(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001));
5844
5845 strncpy(win->event.keyName, keyName, 16);
5846
5847 if (RGFW_isPressed(win, RGFW_ShiftL)) {
5848 ToAscii((UINT) msg.wParam, MapVirtualKey((UINT) msg.wParam, MAPVK_VK_TO_CHAR),
5849 keyboardState, (LPWORD) win->event.keyName, 0);
5850 }
5851
5852 win->event.type = RGFW_keyReleased;
5853 RGFW_keyboard[win->event.keyCode].current = 0;
5854 RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, 0);
5855 break;
5856 }
5857 case WM_KEYDOWN: {
5858 win->event.keyCode = RGFW_apiKeyCodeToRGFW((u32) msg.wParam);
5859
5860 RGFW_keyboard[win->event.keyCode].prev = RGFW_isPressed(win, win->event.keyCode);
5861
5862 static char keyName[16];
5863
5864 {
5865 GetKeyNameTextA((LONG) msg.lParam, keyName, 16);
5866
5867 if ((!(GetKeyState(VK_CAPITAL) & 0x0001) && !(GetKeyState(VK_SHIFT) & 0x8000)) ||
5868 ((GetKeyState(VK_CAPITAL) & 0x0001) && (GetKeyState(VK_SHIFT) & 0x8000))) {
5869 CharLowerBuffA(keyName, 16);
5870 }
5871 }
5872
5873 RGFW_updateLockState(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001));
5874
5875 strncpy(win->event.keyName, keyName, 16);
5876
5877 if (RGFW_isPressed(win, RGFW_ShiftL) & 0x8000) {
5878 ToAscii((UINT) msg.wParam, MapVirtualKey((UINT) msg.wParam, MAPVK_VK_TO_CHAR),
5879 keyboardState, (LPWORD) win->event.keyName, 0);
5880 }
5881
5882 win->event.type = RGFW_keyPressed;
5883 win->event.repeat = RGFW_isPressed(win, win->event.keyCode);
5884 RGFW_keyboard[win->event.keyCode].current = 1;
5885 RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, 1);
5886 break;
5887 }
5888
5889 case WM_MOUSEMOVE:
5890 if ((win->_winArgs & RGFW_HOLD_MOUSE))
5891 break;
5892
5893 win->event.type = RGFW_mousePosChanged;
5894
5895 win->event.point.x = GET_X_LPARAM(msg.lParam);
5896 win->event.point.y = GET_Y_LPARAM(msg.lParam);
5897
5898 RGFW_mousePosCallback(win, win->event.point);
5899
5900 if (win->_winArgs & RGFW_MOUSE_LEFT) {
5901 win->_winArgs ^= RGFW_MOUSE_LEFT;
5902 win->event.type = RGFW_mouseEnter;
5903 RGFW_mouseNotifyCallBack(win, win->event.point, 1);
5904 }
5905
5906 break;
5907
5908 case WM_INPUT: {
5909 if (!(win->_winArgs & RGFW_HOLD_MOUSE))
5910 break;
5911
5912 unsigned size = sizeof(RAWINPUT);
5913 static RAWINPUT raw[sizeof(RAWINPUT)];
5914 GetRawInputData((HRAWINPUT)msg.lParam, RID_INPUT, raw, &size, sizeof(RAWINPUTHEADER));
5915
5916 if (raw->header.dwType != RIM_TYPEMOUSE || (raw->data.mouse.lLastX == 0 && raw->data.mouse.lLastY == 0) )
5917 break;
5918
5919 win->event.type = RGFW_mousePosChanged;
5920 win->event.point.x = raw->data.mouse.lLastX;
5921 win->event.point.y = raw->data.mouse.lLastY;
5922 break;
5923 }
5924
5925 case WM_LBUTTONDOWN:
5926 win->event.button = RGFW_mouseLeft;
5927 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
5928 RGFW_mouseButtons[win->event.button].current = 1;
5929 win->event.type = RGFW_mouseButtonPressed;
5930 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
5931 break;
5932 case WM_RBUTTONDOWN:
5933 win->event.button = RGFW_mouseRight;
5934 win->event.type = RGFW_mouseButtonPressed;
5935 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
5936 RGFW_mouseButtons[win->event.button].current = 1;
5937 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
5938 break;
5939 case WM_MBUTTONDOWN:
5940 win->event.button = RGFW_mouseMiddle;
5941 win->event.type = RGFW_mouseButtonPressed;
5942 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
5943 RGFW_mouseButtons[win->event.button].current = 1;
5944 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
5945 break;
5946
5947 case WM_MOUSEWHEEL:
5948 if (msg.wParam > 0)
5949 win->event.button = RGFW_mouseScrollUp;
5950 else
5951 win->event.button = RGFW_mouseScrollDown;
5952
5953 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
5954 RGFW_mouseButtons[win->event.button].current = 1;
5955
5956 win->event.scroll = (SHORT) HIWORD(msg.wParam) / (double) WHEEL_DELTA;
5957
5958 win->event.type = RGFW_mouseButtonPressed;
5959 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
5960 break;
5961
5962 case WM_LBUTTONUP:
5963
5964 win->event.button = RGFW_mouseLeft;
5965 win->event.type = RGFW_mouseButtonReleased;
5966
5967 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
5968 RGFW_mouseButtons[win->event.button].current = 0;
5969 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0);
5970 break;
5971 case WM_RBUTTONUP:
5972 win->event.button = RGFW_mouseRight;
5973 win->event.type = RGFW_mouseButtonReleased;
5974
5975 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
5976 RGFW_mouseButtons[win->event.button].current = 0;
5977 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0);
5978 break;
5979 case WM_MBUTTONUP:
5980 win->event.button = RGFW_mouseMiddle;
5981 win->event.type = RGFW_mouseButtonReleased;
5982
5983 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
5984 RGFW_mouseButtons[win->event.button].current = 0;
5985 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0);
5986 break;
5987
5988 /*
5989 much of this event is source from glfw
5990 */
5991 case WM_DROPFILES: {
5992 win->event.type = RGFW_dnd_init;
5993
5994 drop = (HDROP) msg.wParam;
5995 POINT pt;
5996
5997 /* Move the mouse to the position of the drop */
5998 DragQueryPoint(drop, &pt);
5999
6000 win->event.point.x = pt.x;
6001 win->event.point.y = pt.y;
6002
6003 RGFW_dndInitCallback(win, win->event.point);
6004 }
6005 break;
6006 case WM_GETMINMAXINFO:
6007 {
6008 if (win->src.maxSize.w == 0 && win->src.maxSize.h == 0)
6009 break;
6010
6011 MINMAXINFO* mmi = (MINMAXINFO*) msg.lParam;
6012 mmi->ptMinTrackSize.x = win->src.minSize.w;
6013 mmi->ptMinTrackSize.y = win->src.minSize.h;
6014 mmi->ptMaxTrackSize.x = win->src.maxSize.w;
6015 mmi->ptMaxTrackSize.y = win->src.maxSize.h;
6016 return 0;
6017 }
6018 default:
6019 win->event.type = 0;
6020 break;
6021 }
6022
6023 TranslateMessage(&msg);
6024 DispatchMessageA(&msg);
6025 }
6026
6027 else
6028 win->event.type = 0;
6029
6030 if (!IsWindow(win->src.window)) {
6031 win->event.type = RGFW_quit;
6032 RGFW_windowQuitCallback(win);
6033 }
6034
6035 if (win->event.type)
6036 return &win->event;
6037 else
6038 return NULL;
6039 }
6040
6041 u8 RGFW_window_isFullscreen(RGFW_window* win) {
6042 assert(win != NULL);
6043
6044 #ifndef __cplusplus
6045 WINDOWPLACEMENT placement = { 0 };
6046 #else
6047 WINDOWPLACEMENT placement = { };
6048 #endif
6049 GetWindowPlacement(win->src.window, &placement);
6050 return placement.showCmd == SW_SHOWMAXIMIZED;
6051 }
6052
6053 u8 RGFW_window_isHidden(RGFW_window* win) {
6054 assert(win != NULL);
6055
6056 return IsWindowVisible(win->src.window) == 0 && !RGFW_window_isMinimized(win);
6057 }
6058
6059 u8 RGFW_window_isMinimized(RGFW_window* win) {
6060 assert(win != NULL);
6061
6062 #ifndef __cplusplus
6063 WINDOWPLACEMENT placement = { 0 };
6064 #else
6065 WINDOWPLACEMENT placement = { };
6066 #endif
6067 GetWindowPlacement(win->src.window, &placement);
6068 return placement.showCmd == SW_SHOWMINIMIZED;
6069 }
6070
6071 u8 RGFW_window_isMaximized(RGFW_window* win) {
6072 assert(win != NULL);
6073
6074 #ifndef __cplusplus
6075 WINDOWPLACEMENT placement = { 0 };
6076 #else
6077 WINDOWPLACEMENT placement = { };
6078 #endif
6079 GetWindowPlacement(win->src.window, &placement);
6080 return placement.showCmd == SW_SHOWMAXIMIZED;
6081 }
6082
6083 typedef struct { int iIndex; HMONITOR hMonitor; } RGFW_mInfo;
6084 BOOL CALLBACK GetMonitorByHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
6085 RGFW_UNUSED(hdcMonitor)
6086 RGFW_UNUSED(lprcMonitor)
6087
6088 RGFW_mInfo* info = (RGFW_mInfo*) dwData;
6089 if (info->hMonitor == hMonitor)
6090 return FALSE;
6091
6092 info->iIndex++;
6093 return TRUE;
6094 }
6095
6096 #ifndef RGFW_NO_MONITOR
6097 RGFW_monitor win32CreateMonitor(HMONITOR src) {
6098 RGFW_monitor monitor;
6099 MONITORINFO monitorInfo;
6100
6101 monitorInfo.cbSize = sizeof(MONITORINFO);
6102 GetMonitorInfoA(src, &monitorInfo);
6103
6104 RGFW_mInfo info;
6105 info.iIndex = 0;
6106 info.hMonitor = src;
6107
6108 /* get the monitor's index */
6109 if (EnumDisplayMonitors(NULL, NULL, GetMonitorByHandle, (LPARAM) &info)) {
6110 DISPLAY_DEVICEA dd;
6111 dd.cb = sizeof(dd);
6112
6113 /* loop through the devices until you find a device with the monitor's index */
6114 size_t deviceIndex;
6115 for (deviceIndex = 0; EnumDisplayDevicesA(0, (DWORD) deviceIndex, &dd, 0); deviceIndex++) {
6116 char* deviceName = dd.DeviceName;
6117 if (EnumDisplayDevicesA(deviceName, info.iIndex, &dd, 0)) {
6118 strncpy(monitor.name, dd.DeviceString, 128); /*!< copy the monitor's name */
6119 break;
6120 }
6121 }
6122 }
6123
6124 monitor.rect.x = monitorInfo.rcWork.left;
6125 monitor.rect.y = monitorInfo.rcWork.top;
6126 monitor.rect.w = monitorInfo.rcWork.right - monitorInfo.rcWork.left;
6127 monitor.rect.h = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;
6128
6129#ifndef RGFW_NO_DPI
6130 #ifndef USER_DEFAULT_SCREEN_DPI
6131 #define USER_DEFAULT_SCREEN_DPI 96
6132 #endif
6133
6134 if (GetDpiForMonitor != NULL) {
6135 u32 x, y;
6136 GetDpiForMonitor(src, MDT_EFFECTIVE_DPI, &x, &y);
6137
6138 monitor.scaleX = (float) (x) / (float) USER_DEFAULT_SCREEN_DPI;
6139 monitor.scaleY = (float) (y) / (float) USER_DEFAULT_SCREEN_DPI;
6140 }
6141#endif
6142
6143 HDC hdc = GetDC(NULL);
6144 /* get pixels per inch */
6145 i32 ppiX = GetDeviceCaps(hdc, LOGPIXELSX);
6146 i32 ppiY = GetDeviceCaps(hdc, LOGPIXELSY);
6147 ReleaseDC(NULL, hdc);
6148
6149 /* Calculate physical height in inches */
6150 monitor.physW = GetSystemMetrics(SM_CYSCREEN) / (float) ppiX;
6151 monitor.physH = GetSystemMetrics(SM_CXSCREEN) / (float) ppiY;
6152
6153 return monitor;
6154 }
6155 #endif /* RGFW_NO_MONITOR */
6156
6157
6158 #ifndef RGFW_NO_MONITOR
6159 RGFW_monitor RGFW_monitors[6];
6160 BOOL CALLBACK GetMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
6161 RGFW_UNUSED(hdcMonitor)
6162 RGFW_UNUSED(lprcMonitor)
6163
6164 RGFW_mInfo* info = (RGFW_mInfo*) dwData;
6165
6166 if (info->iIndex >= 6)
6167 return FALSE;
6168
6169 RGFW_monitors[info->iIndex] = win32CreateMonitor(hMonitor);
6170 info->iIndex++;
6171
6172 return TRUE;
6173 }
6174
6175 RGFW_monitor RGFW_getPrimaryMonitor(void) {
6176 #ifdef __cplusplus
6177 return win32CreateMonitor(MonitorFromPoint({ 0, 0 }, MONITOR_DEFAULTTOPRIMARY));
6178 #else
6179 return win32CreateMonitor(MonitorFromPoint((POINT) { 0, 0 }, MONITOR_DEFAULTTOPRIMARY));
6180 #endif
6181 }
6182
6183 RGFW_monitor* RGFW_getMonitors(void) {
6184 RGFW_mInfo info;
6185 info.iIndex = 0;
6186 while (EnumDisplayMonitors(NULL, NULL, GetMonitorHandle, (LPARAM) &info));
6187
6188 return RGFW_monitors;
6189 }
6190
6191 RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {
6192 HMONITOR src = MonitorFromWindow(win->src.window, MONITOR_DEFAULTTOPRIMARY);
6193 return win32CreateMonitor(src);
6194 }
6195 #endif
6196
6197 HICON RGFW_loadHandleImage(RGFW_window* win, u8* src, RGFW_area a, BOOL icon) {
6198 assert(win != NULL);
6199
6200 u32 i;
6201 HDC dc;
6202 HICON handle;
6203 HBITMAP color, mask;
6204 BITMAPV5HEADER bi;
6205 ICONINFO ii;
6206 u8* target = NULL;
6207 u8* source = src;
6208
6209 ZeroMemory(&bi, sizeof(bi));
6210 bi.bV5Size = sizeof(bi);
6211 bi.bV5Width = a.w;
6212 bi.bV5Height = -((LONG) a.h);
6213 bi.bV5Planes = 1;
6214 bi.bV5BitCount = 32;
6215 bi.bV5Compression = BI_BITFIELDS;
6216 bi.bV5RedMask = 0x00ff0000;
6217 bi.bV5GreenMask = 0x0000ff00;
6218 bi.bV5BlueMask = 0x000000ff;
6219 bi.bV5AlphaMask = 0xff000000;
6220
6221 dc = GetDC(NULL);
6222 color = CreateDIBSection(dc,
6223 (BITMAPINFO*) &bi,
6224 DIB_RGB_COLORS,
6225 (void**) &target,
6226 NULL,
6227 (DWORD) 0);
6228 ReleaseDC(NULL, dc);
6229
6230 mask = CreateBitmap(a.w, a.h, 1, 1, NULL);
6231
6232 for (i = 0; i < a.w * a.h; i++) {
6233 target[0] = source[2];
6234 target[1] = source[1];
6235 target[2] = source[0];
6236 target[3] = source[3];
6237 target += 4;
6238 source += 4;
6239 }
6240
6241 ZeroMemory(&ii, sizeof(ii));
6242 ii.fIcon = icon;
6243 ii.xHotspot = 0;
6244 ii.yHotspot = 0;
6245 ii.hbmMask = mask;
6246 ii.hbmColor = color;
6247
6248 handle = CreateIconIndirect(&ii);
6249
6250 DeleteObject(color);
6251 DeleteObject(mask);
6252
6253 return handle;
6254 }
6255
6256 void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels) {
6257 assert(win != NULL);
6258 RGFW_UNUSED(channels)
6259
6260 HCURSOR cursor = (HCURSOR) RGFW_loadHandleImage(win, image, a, FALSE);
6261 SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) cursor);
6262 SetCursor(cursor);
6263 DestroyCursor(cursor);
6264 }
6265
6266 void RGFW_window_setMouseDefault(RGFW_window* win) {
6267 RGFW_window_setMouseStandard(win, RGFW_MOUSE_ARROW);
6268 }
6269
6270 void RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {
6271 assert(win != NULL);
6272
6273 if (mouse > (sizeof(RGFW_mouseIconSrc) / sizeof(u32)))
6274 return;
6275
6276 char* icon = MAKEINTRESOURCEA(RGFW_mouseIconSrc[mouse]);
6277
6278 SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) LoadCursorA(NULL, icon));
6279 SetCursor(LoadCursorA(NULL, icon));
6280 }
6281
6282 void RGFW_window_hide(RGFW_window* win) {
6283 ShowWindow(win->src.window, SW_HIDE);
6284 }
6285
6286 void RGFW_window_show(RGFW_window* win) {
6287 ShowWindow(win->src.window, SW_RESTORE);
6288 }
6289
6290 void RGFW_window_close(RGFW_window* win) {
6291 assert(win != NULL);
6292
6293#ifdef RGFW_EGL
6294 RGFW_closeEGL(win);
6295#endif
6296
6297 if (win == RGFW_root) {
6298#ifdef RGFW_DIRECTX
6299 RGFW_dxInfo.pDeviceContext->lpVtbl->Release(RGFW_dxInfo.pDeviceContext);
6300 RGFW_dxInfo.pDevice->lpVtbl->Release(RGFW_dxInfo.pDevice);
6301 RGFW_dxInfo.pAdapter->lpVtbl->Release(RGFW_dxInfo.pAdapter);
6302 RGFW_dxInfo.pFactory->lpVtbl->Release(RGFW_dxInfo.pFactory);
6303#endif
6304
6305 if (RGFW_XInput_dll != NULL) {
6306 FreeLibrary(RGFW_XInput_dll);
6307 RGFW_XInput_dll = NULL;
6308 }
6309
6310 #ifndef RGFW_NO_DPI
6311 if (RGFW_Shcore_dll != NULL) {
6312 FreeLibrary(RGFW_Shcore_dll);
6313 RGFW_Shcore_dll = NULL;
6314 }
6315 #endif
6316
6317 if (wglinstance != NULL) {
6318 FreeLibrary(wglinstance);
6319 wglinstance = NULL;
6320 }
6321
6322 RGFW_root = NULL;
6323 }
6324
6325#ifdef RGFW_DIRECTX
6326 win->src.swapchain->lpVtbl->Release(win->src.swapchain);
6327 win->src.renderTargetView->lpVtbl->Release(win->src.renderTargetView);
6328 win->src.pDepthStencilView->lpVtbl->Release(win->src.pDepthStencilView);
6329#endif
6330
6331#ifdef RGFW_BUFFER
6332 DeleteDC(win->src.hdcMem);
6333 DeleteObject(win->src.bitmap);
6334#endif
6335
6336#ifdef RGFW_OPENGL
6337 wglDeleteContext((HGLRC) win->src.ctx); /*!< delete opengl context */
6338#endif
6339 DeleteDC(win->src.hdc); /*!< delete device context */
6340 DestroyWindow(win->src.window); /*!< delete window */
6341
6342#if defined(RGFW_OSMESA)
6343 if (win->buffer != NULL)
6344 RGFW_FREE(win->buffer);
6345#endif
6346
6347#ifdef RGFW_ALLOC_DROPFILES
6348 {
6349 u32 i;
6350 for (i = 0; i < RGFW_MAX_DROPS; i++)
6351 RGFW_FREE(win->event.droppedFiles[i]);
6352
6353
6354 RGFW_FREE(win->event.droppedFiles);
6355 }
6356#endif
6357
6358 RGFW_FREE(win);
6359 }
6360
6361 void RGFW_window_move(RGFW_window* win, RGFW_point v) {
6362 assert(win != NULL);
6363
6364 win->r.x = v.x;
6365 win->r.y = v.y;
6366 SetWindowPos(win->src.window, HWND_TOP, win->r.x, win->r.y, 0, 0, SWP_NOSIZE);
6367 }
6368
6369 void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
6370 assert(win != NULL);
6371
6372 win->r.w = a.w;
6373 win->r.h = a.h;
6374 SetWindowPos(win->src.window, HWND_TOP, 0, 0, win->r.w, win->r.h + win->src.hOffset, SWP_NOMOVE);
6375 }
6376
6377
6378 void RGFW_window_setName(RGFW_window* win, char* name) {
6379 assert(win != NULL);
6380
6381 SetWindowTextA(win->src.window, name);
6382 }
6383
6384 /* sourced from GLFW */
6385 #ifndef RGFW_NO_PASSTHROUGH
6386 void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) {
6387 assert(win != NULL);
6388
6389 COLORREF key = 0;
6390 BYTE alpha = 0;
6391 DWORD flags = 0;
6392 DWORD exStyle = GetWindowLongW(win->src.window, GWL_EXSTYLE);
6393
6394 if (exStyle & WS_EX_LAYERED)
6395 GetLayeredWindowAttributes(win->src.window, &key, &alpha, &flags);
6396
6397 if (passthrough)
6398 exStyle |= (WS_EX_TRANSPARENT | WS_EX_LAYERED);
6399 else
6400 {
6401 exStyle &= ~WS_EX_TRANSPARENT;
6402 // NOTE: Window opacity also needs the layered window style so do not
6403 // remove it if the window is alpha blended
6404 if (exStyle & WS_EX_LAYERED)
6405 {
6406 if (!(flags & LWA_ALPHA))
6407 exStyle &= ~WS_EX_LAYERED;
6408 }
6409 }
6410
6411 SetWindowLongW(win->src.window, GWL_EXSTYLE, exStyle);
6412
6413 if (passthrough) {
6414 SetLayeredWindowAttributes(win->src.window, key, alpha, flags);
6415 }
6416 }
6417 #endif
6418
6419 /* much of this function is sourced from GLFW */
6420 void RGFW_window_setIcon(RGFW_window* win, u8* src, RGFW_area a, i32 channels) {
6421 assert(win != NULL);
6422 #ifndef RGFW_WIN95
6423 RGFW_UNUSED(channels)
6424
6425 HICON handle = RGFW_loadHandleImage(win, src, a, TRUE);
6426
6427 SetClassLongPtrA(win->src.window, GCLP_HICON, (LPARAM) handle);
6428
6429 DestroyIcon(handle);
6430 #else
6431 RGFW_UNUSED(src)
6432 RGFW_UNUSED(a)
6433 RGFW_UNUSED(channels)
6434 #endif
6435 }
6436
6437 char* RGFW_readClipboard(size_t* size) {
6438 /* Open the clipboard */
6439 if (OpenClipboard(NULL) == 0)
6440 return (char*) "";
6441
6442 /* Get the clipboard data as a Unicode string */
6443 HANDLE hData = GetClipboardData(CF_UNICODETEXT);
6444 if (hData == NULL) {
6445 CloseClipboard();
6446 return (char*) "";
6447 }
6448
6449 wchar_t* wstr = (wchar_t*) GlobalLock(hData);
6450
6451 char* text;
6452
6453 {
6454 setlocale(LC_ALL, "en_US.UTF-8");
6455
6456 size_t textLen = wcstombs(NULL, wstr, 0);
6457 if (textLen == 0)
6458 return (char*) "";
6459
6460 text = (char*) RGFW_MALLOC((textLen * sizeof(char)) + 1);
6461
6462 wcstombs(text, wstr, (textLen) +1);
6463
6464 if (size != NULL)
6465 *size = textLen + 1;
6466
6467 text[textLen] = '\0';
6468 }
6469
6470 /* Release the clipboard data */
6471 GlobalUnlock(hData);
6472 CloseClipboard();
6473
6474 return text;
6475 }
6476
6477 void RGFW_writeClipboard(const char* text, u32 textLen) {
6478 HANDLE object;
6479 WCHAR* buffer;
6480
6481 object = GlobalAlloc(GMEM_MOVEABLE, (1 + textLen) * sizeof(WCHAR));
6482 if (!object)
6483 return;
6484
6485 buffer = (WCHAR*) GlobalLock(object);
6486 if (!buffer) {
6487 GlobalFree(object);
6488 return;
6489 }
6490
6491 MultiByteToWideChar(CP_UTF8, 0, text, -1, buffer, textLen);
6492 GlobalUnlock(object);
6493
6494 if (!OpenClipboard(RGFW_root->src.window)) {
6495 GlobalFree(object);
6496 return;
6497 }
6498
6499 EmptyClipboard();
6500 SetClipboardData(CF_UNICODETEXT, object);
6501 CloseClipboard();
6502 }
6503
6504 u16 RGFW_registerJoystick(RGFW_window* win, i32 jsNumber) {
6505 assert(win != NULL);
6506
6507 RGFW_UNUSED(jsNumber)
6508
6509 return RGFW_registerJoystickF(win, (char*) "");
6510 }
6511
6512 u16 RGFW_registerJoystickF(RGFW_window* win, char* file) {
6513 assert(win != NULL);
6514 RGFW_UNUSED(file)
6515
6516 return RGFW_joystickCount - 1;
6517 }
6518
6519 void RGFW_window_moveMouse(RGFW_window* win, RGFW_point p) {
6520 assert(win != NULL);
6521
6522 SetCursorPos(p.x, p.y);
6523 }
6524
6525 #ifdef RGFW_OPENGL
6526 void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
6527 if (win == NULL)
6528 wglMakeCurrent(NULL, NULL);
6529 else
6530 wglMakeCurrent(win->src.hdc, (HGLRC) win->src.ctx);
6531 }
6532 #endif
6533
6534 #ifndef RGFW_EGL
6535 void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) {
6536 assert(win != NULL);
6537
6538 #if defined(RGFW_OPENGL)
6539 typedef BOOL(APIENTRY* PFNWGLSWAPINTERVALEXTPROC)(int interval);
6540 static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
6541 static void* loadSwapFunc = (void*) 1;
6542
6543 if (loadSwapFunc == NULL) {
6544 fprintf(stderr, "wglSwapIntervalEXT not supported\n");
6545 return;
6546 }
6547
6548 if (wglSwapIntervalEXT == NULL) {
6549 loadSwapFunc = (void*) wglGetProcAddress("wglSwapIntervalEXT");
6550 wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) loadSwapFunc;
6551 }
6552
6553 if (wglSwapIntervalEXT(swapInterval) == FALSE)
6554 fprintf(stderr, "Failed to set swap interval\n");
6555 #else
6556 RGFW_UNUSED(swapInterval);
6557 #endif
6558
6559 }
6560 #endif
6561
6562 void RGFW_window_swapBuffers(RGFW_window* win) {
6563 //assert(win != NULL);
6564 /* clear the window*/
6565
6566 if (!(win->_winArgs & RGFW_NO_CPU_RENDER)) {
6567#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
6568 #ifdef RGFW_OSMESA
6569 RGFW_OSMesa_reorganize();
6570 #endif
6571
6572 HGDIOBJ oldbmp = SelectObject(win->src.hdcMem, win->src.bitmap);
6573 BitBlt(win->src.hdc, 0, 0, win->r.w, win->r.h, win->src.hdcMem, 0, 0, SRCCOPY);
6574 SelectObject(win->src.hdcMem, oldbmp);
6575#endif
6576 }
6577
6578 if (!(win->_winArgs & RGFW_NO_GPU_RENDER)) {
6579 #ifdef RGFW_EGL
6580 eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface);
6581 #elif defined(RGFW_OPENGL)
6582 SwapBuffers(win->src.hdc);
6583 #endif
6584
6585 #if defined(RGFW_WINDOWS) && defined(RGFW_DIRECTX)
6586 win->src.swapchain->lpVtbl->Present(win->src.swapchain, 0, 0);
6587 #endif
6588 }
6589 }
6590
6591 char* createUTF8FromWideStringWin32(const WCHAR* source) {
6592 char* target;
6593 i32 size;
6594
6595 size = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL);
6596 if (!size) {
6597 return NULL;
6598 }
6599
6600 target = (char*) RGFW_CALLOC(size, 1);
6601
6602 if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, size, NULL, NULL)) {
6603 RGFW_FREE(target);
6604 return NULL;
6605 }
6606
6607 return target;
6608 }
6609
6610 static inline LARGE_INTEGER RGFW_win32_initTimer(void) {
6611 static LARGE_INTEGER frequency = {{0, 0}};
6612 if (frequency.QuadPart == 0) {
6613 timeBeginPeriod(1);
6614 QueryPerformanceFrequency(&frequency);
6615 }
6616
6617 return frequency;
6618 }
6619
6620 u64 RGFW_getTimeNS(void) {
6621 LARGE_INTEGER frequency = RGFW_win32_initTimer();
6622
6623 LARGE_INTEGER counter;
6624 QueryPerformanceCounter(&counter);
6625
6626 return (u64) ((counter.QuadPart * 1e9) / frequency.QuadPart);
6627 }
6628
6629 u64 RGFW_getTime(void) {
6630 LARGE_INTEGER frequency = RGFW_win32_initTimer();
6631
6632 LARGE_INTEGER counter;
6633 QueryPerformanceCounter(&counter);
6634 return (u64) (counter.QuadPart / (double) frequency.QuadPart);
6635 }
6636
6637 void RGFW_sleep(u64 ms) {
6638 Sleep(ms);
6639 }
6640
6641#ifndef RGFW_NO_THREADS
6642 RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args) { return CreateThread(NULL, 0, ptr, args, 0, NULL); }
6643 void RGFW_cancelThread(RGFW_thread thread) { CloseHandle((HANDLE) thread); }
6644 void RGFW_joinThread(RGFW_thread thread) { WaitForSingleObject((HANDLE) thread, INFINITE); }
6645 void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { SetThreadPriority((HANDLE) thread, priority); }
6646#endif
6647#endif /* RGFW_WINDOWS */
6648
6649/*
6650 End of Windows defines
6651*/
6652
6653
6654
6655/*
6656
6657 Start of MacOS defines
6658
6659
6660*/
6661
6662#if defined(RGFW_MACOS)
6663 /*
6664 based on silicon.h
6665 start of cocoa wrapper
6666 */
6667
6668#include <CoreVideo/CVDisplayLink.h>
6669#include <ApplicationServices/ApplicationServices.h>
6670#include <objc/runtime.h>
6671#include <objc/message.h>
6672#include <mach/mach_time.h>
6673
6674 typedef CGRect NSRect;
6675 typedef CGPoint NSPoint;
6676 typedef CGSize NSSize;
6677
6678 typedef void NSBitmapImageRep;
6679 typedef void NSCursor;
6680 typedef void NSDraggingInfo;
6681 typedef void NSWindow;
6682 typedef void NSApplication;
6683 typedef void NSScreen;
6684 typedef void NSEvent;
6685 typedef void NSString;
6686 typedef void NSOpenGLContext;
6687 typedef void NSPasteboard;
6688 typedef void NSColor;
6689 typedef void NSArray;
6690 typedef void NSImageRep;
6691 typedef void NSImage;
6692 typedef void NSOpenGLView;
6693
6694
6695 typedef const char* NSPasteboardType;
6696 typedef unsigned long NSUInteger;
6697 typedef long NSInteger;
6698 typedef NSInteger NSModalResponse;
6699
6700#ifdef __arm64__
6701 /* ARM just uses objc_msgSend */
6702#define abi_objc_msgSend_stret objc_msgSend
6703#define abi_objc_msgSend_fpret objc_msgSend
6704#else /* __i386__ */
6705 /* x86 just uses abi_objc_msgSend_fpret and (NSColor *)objc_msgSend_id respectively */
6706#define abi_objc_msgSend_stret objc_msgSend_stret
6707#define abi_objc_msgSend_fpret objc_msgSend_fpret
6708#endif
6709
6710#define NSAlloc(nsclass) objc_msgSend_id((id)nsclass, sel_registerName("alloc"))
6711#define objc_msgSend_bool ((BOOL (*)(id, SEL))objc_msgSend)
6712#define objc_msgSend_void ((void (*)(id, SEL))objc_msgSend)
6713#define objc_msgSend_void_id ((void (*)(id, SEL, id))objc_msgSend)
6714#define objc_msgSend_uint ((NSUInteger (*)(id, SEL))objc_msgSend)
6715#define objc_msgSend_void_bool ((void (*)(id, SEL, BOOL))objc_msgSend)
6716#define objc_msgSend_bool_void ((BOOL (*)(id, SEL))objc_msgSend)
6717#define objc_msgSend_void_SEL ((void (*)(id, SEL, SEL))objc_msgSend)
6718#define objc_msgSend_id ((id (*)(id, SEL))objc_msgSend)
6719#define objc_msgSend_id_id ((id (*)(id, SEL, id))objc_msgSend)
6720#define objc_msgSend_id_bool ((BOOL (*)(id, SEL, id))objc_msgSend)
6721#define objc_msgSend_int ((id (*)(id, SEL, int))objc_msgSend)
6722#define objc_msgSend_arr ((id (*)(id, SEL, int))objc_msgSend)
6723#define objc_msgSend_ptr ((id (*)(id, SEL, void*))objc_msgSend)
6724#define objc_msgSend_class ((id (*)(Class, SEL))objc_msgSend)
6725#define objc_msgSend_class_char ((id (*)(Class, SEL, char*))objc_msgSend)
6726
6727 NSApplication* NSApp = NULL;
6728
6729 void NSRelease(id obj) {
6730 objc_msgSend_void(obj, sel_registerName("release"));
6731 }
6732
6733 #define release NSRelease
6734
6735 NSString* NSString_stringWithUTF8String(const char* str) {
6736 return ((id(*)(id, SEL, const char*))objc_msgSend)
6737 ((id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), str);
6738 }
6739
6740 const char* NSString_to_char(NSString* str) {
6741 return ((const char* (*)(id, SEL)) objc_msgSend) (str, sel_registerName("UTF8String"));
6742 }
6743
6744 void si_impl_func_to_SEL_with_name(const char* class_name, const char* register_name, void* function) {
6745 Class selected_class;
6746
6747 if (strcmp(class_name, "NSView") == 0) {
6748 selected_class = objc_getClass("ViewClass");
6749 } else if (strcmp(class_name, "NSWindow") == 0) {
6750 selected_class = objc_getClass("WindowClass");
6751 } else {
6752 selected_class = objc_getClass(class_name);
6753 }
6754
6755 class_addMethod(selected_class, sel_registerName(register_name), (IMP) function, 0);
6756 }
6757
6758 /* Header for the array. */
6759 typedef struct siArrayHeader {
6760 size_t count;
6761 /* TODO(EimaMei): Add a `type_width` later on. */
6762 } siArrayHeader;
6763
6764 /* Gets the header of the siArray. */
6765#define SI_ARRAY_HEADER(s) ((siArrayHeader*)s - 1)
6766
6767 void* si_array_init_reserve(size_t sizeof_element, size_t count) {
6768 siArrayHeader* ptr = malloc(sizeof(siArrayHeader) + (sizeof_element * count));
6769 void* array = ptr + sizeof(siArrayHeader);
6770
6771 siArrayHeader* header = SI_ARRAY_HEADER(array);
6772 header->count = count;
6773
6774 return array;
6775 }
6776
6777#define si_array_len(array) (SI_ARRAY_HEADER(array)->count)
6778#define si_func_to_SEL(class_name, function) si_impl_func_to_SEL_with_name(class_name, #function":", function)
6779 /* Creates an Objective-C method (SEL) from a regular C function with the option to set the register name.*/
6780#define si_func_to_SEL_with_name(class_name, register_name, function) si_impl_func_to_SEL_with_name(class_name, register_name":", function)
6781
6782 unsigned char* NSBitmapImageRep_bitmapData(NSBitmapImageRep* imageRep) {
6783 return ((unsigned char* (*)(id, SEL))objc_msgSend)
6784 (imageRep, sel_registerName("bitmapData"));
6785 }
6786
6787#define NS_ENUM(type, name) type name; enum
6788
6789 typedef NS_ENUM(NSUInteger, NSBitmapFormat) {
6790 NSBitmapFormatAlphaFirst = 1 << 0, // 0 means is alpha last (RGBA, CMYKA, etc.)
6791 NSBitmapFormatAlphaNonpremultiplied = 1 << 1, // 0 means is premultiplied
6792 NSBitmapFormatFloatingPointSamples = 1 << 2, // 0 is integer
6793
6794 NSBitmapFormatSixteenBitLittleEndian API_AVAILABLE(macos(10.10)) = (1 << 8),
6795 NSBitmapFormatThirtyTwoBitLittleEndian API_AVAILABLE(macos(10.10)) = (1 << 9),
6796 NSBitmapFormatSixteenBitBigEndian API_AVAILABLE(macos(10.10)) = (1 << 10),
6797 NSBitmapFormatThirtyTwoBitBigEndian API_AVAILABLE(macos(10.10)) = (1 << 11)
6798 };
6799
6800 NSBitmapImageRep* NSBitmapImageRep_initWithBitmapData(unsigned char** planes, NSInteger width, NSInteger height, NSInteger bps, NSInteger spp, bool alpha, bool isPlanar, const char* colorSpaceName, NSBitmapFormat bitmapFormat, NSInteger rowBytes, NSInteger pixelBits) {
6801 void* func = sel_registerName("initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel:");
6802
6803 return (NSBitmapImageRep*) ((id(*)(id, SEL, unsigned char**, NSInteger, NSInteger, NSInteger, NSInteger, bool, bool, const char*, NSBitmapFormat, NSInteger, NSInteger))objc_msgSend)
6804 (NSAlloc((id)objc_getClass("NSBitmapImageRep")), func, planes, width, height, bps, spp, alpha, isPlanar, NSString_stringWithUTF8String(colorSpaceName), bitmapFormat, rowBytes, pixelBits);
6805 }
6806
6807 NSColor* NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha) {
6808 void* nsclass = objc_getClass("NSColor");
6809 void* func = sel_registerName("colorWithSRGBRed:green:blue:alpha:");
6810 return ((id(*)(id, SEL, CGFloat, CGFloat, CGFloat, CGFloat))objc_msgSend)
6811 (nsclass, func, red, green, blue, alpha);
6812 }
6813
6814 NSCursor* NSCursor_initWithImage(NSImage* newImage, NSPoint aPoint) {
6815 void* func = sel_registerName("initWithImage:hotSpot:");
6816 void* nsclass = objc_getClass("NSCursor");
6817
6818 return (NSCursor*) ((id(*)(id, SEL, id, NSPoint))objc_msgSend)
6819 (NSAlloc(nsclass), func, newImage, aPoint);
6820 }
6821
6822 void NSImage_addRepresentation(NSImage* image, NSImageRep* imageRep) {
6823 void* func = sel_registerName("addRepresentation:");
6824 objc_msgSend_void_id(image, func, imageRep);
6825 }
6826
6827 NSImage* NSImage_initWithSize(NSSize size) {
6828 void* func = sel_registerName("initWithSize:");
6829 return ((id(*)(id, SEL, NSSize))objc_msgSend)
6830 (NSAlloc((id)objc_getClass("NSImage")), func, size);
6831 }
6832#define NS_OPENGL_ENUM_DEPRECATED(minVers, maxVers) API_AVAILABLE(macos(minVers))
6833 typedef NS_ENUM(NSInteger, NSOpenGLContextParameter) {
6834 NSOpenGLContextParameterSwapInterval NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 222, /* 1 param. 0 -> Don't sync, 1 -> Sync to vertical retrace */
6835 NSOpenGLContextParametectxaceOrder NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 235, /* 1 param. 1 -> Above Window (default), -1 -> Below Window */
6836 NSOpenGLContextParametectxaceOpacity NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 236, /* 1 param. 1-> Surface is opaque (default), 0 -> non-opaque */
6837 NSOpenGLContextParametectxaceBackingSize NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 304, /* 2 params. Width/height of surface backing size */
6838 NSOpenGLContextParameterReclaimResources NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 308, /* 0 params. */
6839 NSOpenGLContextParameterCurrentRendererID NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 309, /* 1 param. Retrieves the current renderer ID */
6840 NSOpenGLContextParameterGPUVertexProcessing NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 310, /* 1 param. Currently processing vertices with GPU (get) */
6841 NSOpenGLContextParameterGPUFragmentProcessing NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 311, /* 1 param. Currently processing fragments with GPU (get) */
6842 NSOpenGLContextParameterHasDrawable NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 314, /* 1 param. Boolean returned if drawable is attached */
6843 NSOpenGLContextParameterMPSwapsInFlight NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 315, /* 1 param. Max number of swaps queued by the MP GL engine */
6844
6845 NSOpenGLContextParameterSwapRectangle API_DEPRECATED("", macos(10.0, 10.14)) = 200, /* 4 params. Set or get the swap rectangle {x, y, w, h} */
6846 NSOpenGLContextParameterSwapRectangleEnable API_DEPRECATED("", macos(10.0, 10.14)) = 201, /* Enable or disable the swap rectangle */
6847 NSOpenGLContextParameterRasterizationEnable API_DEPRECATED("", macos(10.0, 10.14)) = 221, /* Enable or disable all rasterization */
6848 NSOpenGLContextParameterStateValidation API_DEPRECATED("", macos(10.0, 10.14)) = 301, /* Validate state for multi-screen functionality */
6849 NSOpenGLContextParametectxaceSurfaceVolatile API_DEPRECATED("", macos(10.0, 10.14)) = 306, /* 1 param. Surface volatile state */
6850 };
6851
6852
6853 void NSOpenGLContext_setValues(NSOpenGLContext* context, const int* vals, NSOpenGLContextParameter param) {
6854 void* func = sel_registerName("setValues:forParameter:");
6855 ((void (*)(id, SEL, const int*, NSOpenGLContextParameter))objc_msgSend)
6856 (context, func, vals, param);
6857 }
6858
6859 void* NSOpenGLPixelFormat_initWithAttributes(const uint32_t* attribs) {
6860 void* func = sel_registerName("initWithAttributes:");
6861 return (void*) ((id(*)(id, SEL, const uint32_t*))objc_msgSend)
6862 (NSAlloc((id)objc_getClass("NSOpenGLPixelFormat")), func, attribs);
6863 }
6864
6865 NSOpenGLView* NSOpenGLView_initWithFrame(NSRect frameRect, uint32_t* format) {
6866 void* func = sel_registerName("initWithFrame:pixelFormat:");
6867 return (NSOpenGLView*) ((id(*)(id, SEL, NSRect, uint32_t*))objc_msgSend)
6868 (NSAlloc((id)objc_getClass("NSOpenGLView")), func, frameRect, format);
6869 }
6870
6871 void NSCursor_performSelector(NSCursor* cursor, void* selector) {
6872 void* func = sel_registerName("performSelector:");
6873 objc_msgSend_void_SEL(cursor, func, selector);
6874 }
6875
6876 NSPasteboard* NSPasteboard_generalPasteboard(void) {
6877 return (NSPasteboard*) objc_msgSend_id((id)objc_getClass("NSPasteboard"), sel_registerName("generalPasteboard"));
6878 }
6879
6880 NSString** cstrToNSStringArray(char** strs, size_t len) {
6881 static NSString* nstrs[6];
6882 size_t i;
6883 for (i = 0; i < len; i++)
6884 nstrs[i] = NSString_stringWithUTF8String(strs[i]);
6885
6886 return nstrs;
6887 }
6888
6889 const char* NSPasteboard_stringForType(NSPasteboard* pasteboard, NSPasteboardType dataType) {
6890 void* func = sel_registerName("stringForType:");
6891 return (const char*) NSString_to_char(((id(*)(id, SEL, const char*))objc_msgSend)(pasteboard, func, NSString_stringWithUTF8String(dataType)));
6892 }
6893
6894 NSArray* c_array_to_NSArray(void* array, size_t len) {
6895 SEL func = sel_registerName("initWithObjects:count:");
6896 void* nsclass = objc_getClass("NSArray");
6897 return ((id (*)(id, SEL, void*, NSUInteger))objc_msgSend)
6898 (NSAlloc(nsclass), func, array, len);
6899 }
6900
6901 void NSregisterForDraggedTypes(void* view, NSPasteboardType* newTypes, size_t len) {
6902 NSString** ntypes = cstrToNSStringArray((char**)newTypes, len);
6903
6904 NSArray* array = c_array_to_NSArray(ntypes, len);
6905 objc_msgSend_void_id(view, sel_registerName("registerForDraggedTypes:"), array);
6906 NSRelease(array);
6907 }
6908
6909 NSInteger NSPasteBoard_declareTypes(NSPasteboard* pasteboard, NSPasteboardType* newTypes, size_t len, void* owner) {
6910 NSString** ntypes = cstrToNSStringArray((char**)newTypes, len);
6911
6912 void* func = sel_registerName("declareTypes:owner:");
6913
6914 NSArray* array = c_array_to_NSArray(ntypes, len);
6915
6916 NSInteger output = ((NSInteger(*)(id, SEL, id, void*))objc_msgSend)
6917 (pasteboard, func, array, owner);
6918 NSRelease(array);
6919
6920 return output;
6921 }
6922
6923 bool NSPasteBoard_setString(NSPasteboard* pasteboard, const char* stringToWrite, NSPasteboardType dataType) {
6924 void* func = sel_registerName("setString:forType:");
6925 return ((bool (*)(id, SEL, id, NSPasteboardType))objc_msgSend)
6926 (pasteboard, func, NSString_stringWithUTF8String(stringToWrite), NSString_stringWithUTF8String(dataType));
6927 }
6928
6929 void NSRetain(id obj) { objc_msgSend_void(obj, sel_registerName("retain")); }
6930
6931 typedef enum NSApplicationActivationPolicy {
6932 NSApplicationActivationPolicyRegular,
6933 NSApplicationActivationPolicyAccessory,
6934 NSApplicationActivationPolicyProhibited
6935 } NSApplicationActivationPolicy;
6936
6937 typedef NS_ENUM(u32, NSBackingStoreType) {
6938 NSBackingStoreRetained = 0,
6939 NSBackingStoreNonretained = 1,
6940 NSBackingStoreBuffered = 2
6941 };
6942
6943 typedef NS_ENUM(u32, NSWindowStyleMask) {
6944 NSWindowStyleMaskBorderless = 0,
6945 NSWindowStyleMaskTitled = 1 << 0,
6946 NSWindowStyleMaskClosable = 1 << 1,
6947 NSWindowStyleMaskMiniaturizable = 1 << 2,
6948 NSWindowStyleMaskResizable = 1 << 3,
6949 NSWindowStyleMaskTexturedBackground = 1 << 8, /* deprecated */
6950 NSWindowStyleMaskUnifiedTitleAndToolbar = 1 << 12,
6951 NSWindowStyleMaskFullScreen = 1 << 14,
6952 NSWindowStyleMaskFullSizeContentView = 1 << 15,
6953 NSWindowStyleMaskUtilityWindow = 1 << 4,
6954 NSWindowStyleMaskDocModalWindow = 1 << 6,
6955 NSWindowStyleMaskNonactivatingPanel = 1 << 7,
6956 NSWindowStyleMaskHUDWindow = 1 << 13
6957 };
6958
6959 NSPasteboardType const NSPasteboardTypeString = "public.utf8-plain-text"; // Replaces NSStringPboardType
6960
6961
6962 typedef NS_ENUM(i32, NSDragOperation) {
6963 NSDragOperationNone = 0,
6964 NSDragOperationCopy = 1,
6965 NSDragOperationLink = 2,
6966 NSDragOperationGeneric = 4,
6967 NSDragOperationPrivate = 8,
6968 NSDragOperationMove = 16,
6969 NSDragOperationDelete = 32,
6970 NSDragOperationEvery = ULONG_MAX,
6971
6972 //NSDragOperationAll_Obsolete API_DEPRECATED("", macos(10.0,10.10)) = 15, // Use NSDragOperationEvery
6973 //NSDragOperationAll API_DEPRECATED("", macos(10.0,10.10)) = NSDragOperationAll_Obsolete, // Use NSDragOperationEvery
6974 };
6975
6976 void* NSArray_objectAtIndex(NSArray* array, NSUInteger index) {
6977 void* func = sel_registerName("objectAtIndex:");
6978 return ((id(*)(id, SEL, NSUInteger))objc_msgSend)(array, func, index);
6979 }
6980
6981 const char** NSPasteboard_readObjectsForClasses(NSPasteboard* pasteboard, Class* classArray, size_t len, void* options) {
6982 void* func = sel_registerName("readObjectsForClasses:options:");
6983
6984 NSArray* array = c_array_to_NSArray(classArray, len);
6985
6986 NSArray* output = (NSArray*) ((id(*)(id, SEL, id, void*))objc_msgSend)
6987 (pasteboard, func, array, options);
6988
6989 NSRelease(array);
6990 NSUInteger count = ((NSUInteger(*)(id, SEL))objc_msgSend)(output, sel_registerName("count"));
6991
6992 const char** res = si_array_init_reserve(sizeof(const char*), count);
6993
6994 void* path_func = sel_registerName("path");
6995
6996 for (NSUInteger i = 0; i < count; i++) {
6997 void* url = NSArray_objectAtIndex(output, i);
6998 NSString* url_str = ((id(*)(id, SEL))objc_msgSend)(url, path_func);
6999 res[i] = NSString_to_char(url_str);
7000 }
7001
7002 return res;
7003 }
7004
7005 void* NSWindow_contentView(NSWindow* window) {
7006 void* func = sel_registerName("contentView");
7007 return objc_msgSend_id(window, func);
7008 }
7009
7010 /*
7011 End of cocoa wrapper
7012 */
7013
7014 char* RGFW_mouseIconSrc[] = {"arrowCursor", "arrowCursor", "IBeamCursor", "crosshairCursor", "pointingHandCursor", "resizeLeftRightCursor", "resizeUpDownCursor", "_windowResizeNorthWestSouthEastCursor", "_windowResizeNorthEastSouthWestCursor", "closedHandCursor", "operationNotAllowedCursor"};
7015
7016 void* RGFWnsglFramework = NULL;
7017
7018#ifdef RGFW_OPENGL
7019 void* RGFW_getProcAddress(const char* procname) {
7020 if (RGFWnsglFramework == NULL)
7021 RGFWnsglFramework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
7022
7023 CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, procname, kCFStringEncodingASCII);
7024
7025 void* symbol = CFBundleGetFunctionPointerForName(RGFWnsglFramework, symbolName);
7026
7027 CFRelease(symbolName);
7028
7029 return symbol;
7030 }
7031#endif
7032
7033 CVReturn displayCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* inNow, const CVTimeStamp* inOutputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext) {
7034 RGFW_UNUSED(displayLink) RGFW_UNUSED(inNow) RGFW_UNUSED(inOutputTime) RGFW_UNUSED(flagsIn) RGFW_UNUSED(flagsOut) RGFW_UNUSED(displayLinkContext)
7035 return kCVReturnSuccess;
7036 }
7037
7038 id NSWindow_delegate(RGFW_window* win) {
7039 return (id) objc_msgSend_id(win->src.window, sel_registerName("delegate"));
7040 }
7041
7042 u32 RGFW_OnClose(void* self) {
7043 RGFW_window* win = NULL;
7044 object_getInstanceVariable(self, "RGFW_window", (void*)&win);
7045 if (win == NULL)
7046 return true;
7047
7048 win->event.type = RGFW_quit;
7049 RGFW_windowQuitCallback(win);
7050
7051 return true;
7052 }
7053
7054 /* NOTE(EimaMei): Fixes the constant clicking when the app is running under a terminal. */
7055 bool acceptsFirstResponder(void) { return true; }
7056 bool performKeyEquivalent(NSEvent* event) { RGFW_UNUSED(event); return true; }
7057
7058 NSDragOperation draggingEntered(id self, SEL sel, id sender) {
7059 RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel);
7060
7061 return NSDragOperationCopy;
7062 }
7063 NSDragOperation draggingUpdated(id self, SEL sel, id sender) {
7064 RGFW_UNUSED(sel);
7065
7066 RGFW_window* win = NULL;
7067 object_getInstanceVariable(self, "RGFW_window", (void*)&win);
7068 if (win == NULL)
7069 return 0;
7070
7071 if (!(win->_winArgs & RGFW_ALLOW_DND)) {
7072 return 0;
7073 }
7074
7075 win->event.type = RGFW_dnd_init;
7076 win->src.dndPassed = 0;
7077
7078 NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation"));
7079
7080 win->event.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y));
7081 RGFW_dndInitCallback(win, win->event.point);
7082
7083 return NSDragOperationCopy;
7084 }
7085 bool prepareForDragOperation(id self) {
7086 RGFW_window* win = NULL;
7087 object_getInstanceVariable(self, "RGFW_window", (void*)&win);
7088 if (win == NULL)
7089 return true;
7090
7091 if (!(win->_winArgs & RGFW_ALLOW_DND)) {
7092 return false;
7093 }
7094
7095 return true;
7096 }
7097
7098 void RGFW__osxDraggingEnded(id self, SEL sel, id sender) { RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); return; }
7099
7100 /* NOTE(EimaMei): Usually, you never need 'id self, SEL cmd' for C -> Obj-C methods. This isn't the case. */
7101 bool performDragOperation(id self, SEL sel, id sender) {
7102 RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel);
7103
7104 RGFW_window* win = NULL;
7105 object_getInstanceVariable(self, "RGFW_window", (void*)&win);
7106
7107 if (win == NULL)
7108 return false;
7109
7110 // NSPasteboard* pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard"));
7111
7112 /////////////////////////////
7113 id pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard"));
7114
7115 // Get the types of data available on the pasteboard
7116 id types = objc_msgSend_id(pasteBoard, sel_registerName("types"));
7117
7118 // Get the string type for file URLs
7119 id fileURLsType = objc_msgSend_class_char(objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "NSFilenamesPboardType");
7120
7121 // Check if the pasteboard contains file URLs
7122 if (objc_msgSend_id_bool(types, sel_registerName("containsObject:"), fileURLsType) == 0) {
7123 #ifdef RGFW_DEBUG
7124 printf("No files found on the pasteboard.\n");
7125 #endif
7126
7127 return 0;
7128 }
7129
7130 id fileURLs = objc_msgSend_id_id(pasteBoard, sel_registerName("propertyListForType:"), fileURLsType);
7131 int count = ((int (*)(id, SEL))objc_msgSend)(fileURLs, sel_registerName("count"));
7132
7133 if (count == 0)
7134 return 0;
7135
7136 for (int i = 0; i < count; i++) {
7137 id fileURL = objc_msgSend_arr(fileURLs, sel_registerName("objectAtIndex:"), i);
7138 const char *filePath = ((const char* (*)(id, SEL))objc_msgSend)(fileURL, sel_registerName("UTF8String"));
7139 strncpy(win->event.droppedFiles[i], filePath, RGFW_MAX_PATH);
7140 win->event.droppedFiles[i][RGFW_MAX_PATH - 1] = '\0';
7141 }
7142 win->event.droppedFilesCount = count;
7143
7144 win->event.type = RGFW_dnd;
7145 win->src.dndPassed = 0;
7146
7147 NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation"));
7148 win->event.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y));
7149
7150 RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount);
7151
7152 return false;
7153 }
7154
7155 static void NSMoveToResourceDir(void) {
7156 /* sourced from glfw */
7157 char resourcesPath[255];
7158
7159 CFBundleRef bundle = CFBundleGetMainBundle();
7160 if (!bundle)
7161 return;
7162
7163 CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);
7164 CFStringRef last = CFURLCopyLastPathComponent(resourcesURL);
7165
7166 if (
7167 CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo ||
7168 CFURLGetFileSystemRepresentation(resourcesURL, true, (u8*) resourcesPath, 255) == 0
7169 ) {
7170 CFRelease(last);
7171 CFRelease(resourcesURL);
7172 return;
7173 }
7174
7175 CFRelease(last);
7176 CFRelease(resourcesURL);
7177
7178 chdir(resourcesPath);
7179 }
7180
7181
7182 NSSize RGFW__osxWindowResize(void* self, SEL sel, NSSize frameSize) {
7183 RGFW_UNUSED(sel);
7184
7185 RGFW_window* win = NULL;
7186 object_getInstanceVariable(self, "RGFW_window", (void*)&win);
7187 if (win == NULL)
7188 return frameSize;
7189
7190 win->r.w = frameSize.width;
7191 win->r.h = frameSize.height;
7192 win->event.type = RGFW_windowResized;
7193 RGFW_windowResizeCallback(win, win->r);
7194 return frameSize;
7195 }
7196
7197 void RGFW__osxWindowMove(void* self, SEL sel) {
7198 RGFW_UNUSED(sel);
7199
7200 RGFW_window* win = NULL;
7201 object_getInstanceVariable(self, "RGFW_window", (void*)&win);
7202 if (win == NULL)
7203 return;
7204
7205 NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)(win->src.window, sel_registerName("frame"));
7206 win->r.x = (i32) frame.origin.x;
7207 win->r.y = (i32) frame.origin.y;
7208
7209 win->event.type = RGFW_windowMoved;
7210 RGFW_windowMoveCallback(win, win->r);
7211 }
7212
7213 void RGFW__osxUpdateLayer(void* self, SEL sel) {
7214 RGFW_UNUSED(sel);
7215
7216 RGFW_window* win = NULL;
7217 object_getInstanceVariable(self, "RGFW_window", (void*)&win);
7218 if (win == NULL)
7219 return;
7220
7221 win->event.type = RGFW_windowRefresh;
7222 RGFW_windowRefreshCallback(win);
7223 }
7224
7225 RGFWDEF void RGFW_init_buffer(RGFW_window* win);
7226 void RGFW_init_buffer(RGFW_window* win) {
7227 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
7228 if (RGFW_bufferSize.w == 0 && RGFW_bufferSize.h == 0)
7229 RGFW_bufferSize = RGFW_getScreenSize();
7230
7231 win->buffer = RGFW_MALLOC(RGFW_bufferSize.w * RGFW_bufferSize.h * 4);
7232
7233 #ifdef RGFW_OSMESA
7234 win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL);
7235 OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, win->r.w, win->r.h);
7236 #endif
7237 #else
7238 RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
7239 #endif
7240 }
7241
7242
7243 void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer) {
7244 objc_msgSend_void_id(win->src.view, sel_registerName("setLayer"), layer);
7245 }
7246
7247 void* RGFW_cocoaGetLayer(void) {
7248 return objc_msgSend_class(objc_getClass("CAMetalLayer"), sel_registerName("layer"));
7249 }
7250
7251
7252 NSPasteboardType const NSPasteboardTypeURL = "public.url";
7253 NSPasteboardType const NSPasteboardTypeFileURL = "public.file-url";
7254
7255 RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) {
7256 static u8 RGFW_loaded = 0;
7257
7258 /* NOTE(EimaMei): Why does Apple hate good code? Like wtf, who thought of methods being a great idea???
7259 Imagine a universe, where MacOS had a proper system API (we would probably have like 20% better performance).
7260 */
7261 si_func_to_SEL_with_name("NSObject", "windowShouldClose", RGFW_OnClose);
7262
7263 /* NOTE(EimaMei): Fixes the 'Boop' sfx from constantly playing each time you click a key. Only a problem when running in the terminal. */
7264 si_func_to_SEL("NSWindow", acceptsFirstResponder);
7265 si_func_to_SEL("NSWindow", performKeyEquivalent);
7266
7267 // RR Create an autorelease pool
7268 id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
7269 pool = objc_msgSend_id(pool, sel_registerName("init"));
7270
7271 if (NSApp == NULL) {
7272 NSApp = objc_msgSend_id((id)objc_getClass("NSApplication"), sel_registerName("sharedApplication"));
7273
7274 ((void (*)(id, SEL, NSUInteger))objc_msgSend)
7275 (NSApp, sel_registerName("setActivationPolicy:"), NSApplicationActivationPolicyRegular);
7276 }
7277
7278 RGFW_window* win = RGFW_window_basic_init(rect, args);
7279
7280 RGFW_window_setMouseDefault(win);
7281
7282 NSRect windowRect;
7283 windowRect.origin.x = win->r.x;
7284 windowRect.origin.y = win->r.y;
7285 windowRect.size.width = win->r.w;
7286 windowRect.size.height = win->r.h;
7287
7288 NSBackingStoreType macArgs = NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSBackingStoreBuffered | NSWindowStyleMaskTitled;
7289
7290 if (!(args & RGFW_NO_RESIZE))
7291 macArgs |= NSWindowStyleMaskResizable;
7292 if (!(args & RGFW_NO_BORDER))
7293 macArgs |= NSWindowStyleMaskTitled;
7294 else
7295 macArgs = NSWindowStyleMaskBorderless;
7296 {
7297 void* nsclass = objc_getClass("NSWindow");
7298 void* func = sel_registerName("initWithContentRect:styleMask:backing:defer:");
7299
7300 win->src.window = ((id(*)(id, SEL, NSRect, NSWindowStyleMask, NSBackingStoreType, bool))objc_msgSend)
7301 (NSAlloc(nsclass), func, windowRect, macArgs, macArgs, false);
7302 }
7303
7304 NSString* str = NSString_stringWithUTF8String(name);
7305 objc_msgSend_void_id(win->src.window, sel_registerName("setTitle:"), str);
7306
7307#ifdef RGFW_EGL
7308 if ((args & RGFW_NO_INIT_API) == 0)
7309 RGFW_createOpenGLContext(win);
7310#endif
7311
7312#ifdef RGFW_OPENGL
7313 if ((args & RGFW_NO_INIT_API) == 0) {
7314 void* attrs = RGFW_initFormatAttribs(args & RGFW_OPENGL_SOFTWARE);
7315 void* format = NSOpenGLPixelFormat_initWithAttributes(attrs);
7316
7317 if (format == NULL) {
7318 printf("Failed to load pixel format for OpenGL\n");
7319
7320 void* attrs = RGFW_initFormatAttribs(1);
7321 format = NSOpenGLPixelFormat_initWithAttributes(attrs);
7322 if (format == NULL)
7323 printf("and loading software rendering OpenGL failed\n");
7324 else
7325 printf("Switching to software rendering\n");
7326 }
7327
7328 /* the pixel format can be passed directly to opengl context creation to create a context
7329 this is because the format also includes information about the opengl version (which may be a bad thing) */
7330 win->src.view = NSOpenGLView_initWithFrame((NSRect){{0, 0}, {win->r.w, win->r.h}}, format);
7331 objc_msgSend_void(win->src.view, sel_registerName("prepareOpenGL"));
7332 win->src.ctx = objc_msgSend_id(win->src.view, sel_registerName("openGLContext"));
7333 } else
7334#endif
7335 {
7336 NSRect contentRect = (NSRect){{0, 0}, {win->r.w, win->r.h}};
7337 win->src.view = ((id(*)(id, SEL, NSRect))objc_msgSend)
7338 (NSAlloc((id)objc_getClass("NSView")), sel_registerName("initWithFrame:"),
7339 contentRect);
7340 }
7341
7342 void* contentView = NSWindow_contentView(win->src.window);
7343 objc_msgSend_void_bool(contentView, sel_registerName("setWantsLayer:"), true);
7344
7345 objc_msgSend_void_id(win->src.window, sel_registerName("setContentView:"), win->src.view);
7346
7347#ifdef RGFW_OPENGL
7348 if ((args & RGFW_NO_INIT_API) == 0)
7349 objc_msgSend_void(win->src.ctx, sel_registerName("makeCurrentContext"));
7350#endif
7351 if (args & RGFW_TRANSPARENT_WINDOW) {
7352#ifdef RGFW_OPENGL
7353 if ((args & RGFW_NO_INIT_API) == 0) {
7354 i32 opacity = 0;
7355 #define NSOpenGLCPSurfaceOpacity 236
7356 NSOpenGLContext_setValues(win->src.ctx, &opacity, NSOpenGLCPSurfaceOpacity);
7357 }
7358#endif
7359
7360 objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), false);
7361
7362 objc_msgSend_void_id(win->src.window, sel_registerName("setBackgroundColor:"),
7363 NSColor_colorWithSRGB(0, 0, 0, 0));
7364 }
7365
7366 win->src.display = CGMainDisplayID();
7367 CVDisplayLinkCreateWithCGDisplay(win->src.display, (CVDisplayLinkRef*)&win->src.displayLink);
7368 CVDisplayLinkSetOutputCallback(win->src.displayLink, displayCallback, win);
7369 CVDisplayLinkStart(win->src.displayLink);
7370
7371 RGFW_init_buffer(win);
7372
7373 #ifndef RGFW_NO_MONITOR
7374 if (args & RGFW_SCALE_TO_MONITOR)
7375 RGFW_window_scaleToMonitor(win);
7376 #endif
7377
7378 if (args & RGFW_CENTER) {
7379 RGFW_area screenR = RGFW_getScreenSize();
7380 RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2));
7381 }
7382
7383 if (args & RGFW_HIDE_MOUSE)
7384 RGFW_window_showMouse(win, 0);
7385
7386 if (args & RGFW_COCOA_MOVE_TO_RESOURCE_DIR)
7387 NSMoveToResourceDir();
7388
7389 Class delegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "WindowDelegate", 0);
7390
7391 class_addIvar(
7392 delegateClass, "RGFW_window",
7393 sizeof(RGFW_window*), rint(log2(sizeof(RGFW_window*))),
7394 "L"
7395 );
7396
7397 class_addMethod(delegateClass, sel_registerName("windowWillResize:toSize:"), (IMP) RGFW__osxWindowResize, "{NSSize=ff}@:{NSSize=ff}");
7398 class_addMethod(delegateClass, sel_registerName("updateLayer:"), (IMP) RGFW__osxUpdateLayer, "");
7399 class_addMethod(delegateClass, sel_registerName("windowWillMove:"), (IMP) RGFW__osxWindowMove, "");
7400 class_addMethod(delegateClass, sel_registerName("windowDidMove:"), (IMP) RGFW__osxWindowMove, "");
7401 class_addMethod(delegateClass, sel_registerName("draggingEntered:"), (IMP)draggingEntered, "l@:@");
7402 class_addMethod(delegateClass, sel_registerName("draggingUpdated:"), (IMP)draggingUpdated, "l@:@");
7403 class_addMethod(delegateClass, sel_registerName("draggingExited:"), (IMP)RGFW__osxDraggingEnded, "v@:@");
7404 class_addMethod(delegateClass, sel_registerName("draggingEnded:"), (IMP)RGFW__osxDraggingEnded, "v@:@");
7405 class_addMethod(delegateClass, sel_registerName("prepareForDragOperation:"), (IMP)prepareForDragOperation, "B@:@");
7406 class_addMethod(delegateClass, sel_registerName("performDragOperation:"), (IMP)performDragOperation, "B@:@");
7407
7408 id delegate = objc_msgSend_id(NSAlloc(delegateClass), sel_registerName("init"));
7409
7410 object_setInstanceVariable(delegate, "RGFW_window", win);
7411
7412 objc_msgSend_void_id(win->src.window, sel_registerName("setDelegate:"), delegate);
7413
7414 if (args & RGFW_ALLOW_DND) {
7415 win->_winArgs |= RGFW_ALLOW_DND;
7416
7417 NSPasteboardType types[] = {NSPasteboardTypeURL, NSPasteboardTypeFileURL, NSPasteboardTypeString};
7418 NSregisterForDraggedTypes(win->src.window, types, 3);
7419 }
7420
7421 // Show the window
7422 objc_msgSend_void_bool(NSApp, sel_registerName("activateIgnoringOtherApps:"), true);
7423 ((id(*)(id, SEL, SEL))objc_msgSend)(win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL);
7424 objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), true);
7425
7426 if (!RGFW_loaded) {
7427 objc_msgSend_void(win->src.window, sel_registerName("makeMainWindow"));
7428
7429 RGFW_loaded = 1;
7430 }
7431
7432 objc_msgSend_void(win->src.window, sel_registerName("makeKeyWindow"));
7433
7434 objc_msgSend_void(NSApp, sel_registerName("finishLaunching"));
7435
7436 if (RGFW_root == NULL)
7437 RGFW_root = win;
7438
7439 NSRetain(win->src.window);
7440 NSRetain(NSApp);
7441
7442 return win;
7443 }
7444
7445 void RGFW_window_setBorder(RGFW_window* win, u8 border) {
7446 NSBackingStoreType storeType = NSWindowStyleMaskBorderless;
7447 if (!border) {
7448 storeType = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;
7449 }
7450 if (!(win->_winArgs & RGFW_NO_RESIZE)) {
7451 storeType |= NSWindowStyleMaskResizable;
7452 }
7453
7454 ((void (*)(id, SEL, NSBackingStoreType))objc_msgSend)(win->src.window, sel_registerName("setStyleMask:"), storeType);
7455
7456 objc_msgSend_void_bool(win->src.window, sel_registerName("setHasShadow:"), border);
7457 }
7458
7459 RGFW_area RGFW_getScreenSize(void) {
7460 static CGDirectDisplayID display = 0;
7461
7462 if (display == 0)
7463 display = CGMainDisplayID();
7464
7465 return RGFW_AREA(CGDisplayPixelsWide(display), CGDisplayPixelsHigh(display));
7466 }
7467
7468 RGFW_point RGFW_getGlobalMousePoint(void) {
7469 assert(RGFW_root != NULL);
7470
7471 CGEventRef e = CGEventCreate(NULL);
7472 CGPoint point = CGEventGetLocation(e);
7473 CFRelease(e);
7474
7475 return RGFW_POINT((u32) point.x, (u32) point.y); /*!< the point is loaded during event checks */
7476 }
7477
7478 RGFW_point RGFW_window_getMousePoint(RGFW_window* win) {
7479 NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(win->src.window, sel_registerName("mouseLocationOutsideOfEventStream"));
7480
7481 return RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y));
7482 }
7483
7484 u32 RGFW_keysPressed[10]; /*10 keys at a time*/
7485 typedef NS_ENUM(u32, NSEventType) { /* various types of events */
7486 NSEventTypeLeftMouseDown = 1,
7487 NSEventTypeLeftMouseUp = 2,
7488 NSEventTypeRightMouseDown = 3,
7489 NSEventTypeRightMouseUp = 4,
7490 NSEventTypeMouseMoved = 5,
7491 NSEventTypeLeftMouseDragged = 6,
7492 NSEventTypeRightMouseDragged = 7,
7493 NSEventTypeMouseEntered = 8,
7494 NSEventTypeMouseExited = 9,
7495 NSEventTypeKeyDown = 10,
7496 NSEventTypeKeyUp = 11,
7497 NSEventTypeFlagsChanged = 12,
7498 NSEventTypeAppKitDefined = 13,
7499 NSEventTypeSystemDefined = 14,
7500 NSEventTypeApplicationDefined = 15,
7501 NSEventTypePeriodic = 16,
7502 NSEventTypeCursorUpdate = 17,
7503 NSEventTypeScrollWheel = 22,
7504 NSEventTypeTabletPoint = 23,
7505 NSEventTypeTabletProximity = 24,
7506 NSEventTypeOtherMouseDown = 25,
7507 NSEventTypeOtherMouseUp = 26,
7508 NSEventTypeOtherMouseDragged = 27,
7509 /* The following event types are available on some hardware on 10.5.2 and later */
7510 NSEventTypeGesture API_AVAILABLE(macos(10.5)) = 29,
7511 NSEventTypeMagnify API_AVAILABLE(macos(10.5)) = 30,
7512 NSEventTypeSwipe API_AVAILABLE(macos(10.5)) = 31,
7513 NSEventTypeRotate API_AVAILABLE(macos(10.5)) = 18,
7514 NSEventTypeBeginGesture API_AVAILABLE(macos(10.5)) = 19,
7515 NSEventTypeEndGesture API_AVAILABLE(macos(10.5)) = 20,
7516
7517 NSEventTypeSmartMagnify API_AVAILABLE(macos(10.8)) = 32,
7518 NSEventTypeQuickLook API_AVAILABLE(macos(10.8)) = 33,
7519
7520 NSEventTypePressure API_AVAILABLE(macos(10.10.3)) = 34,
7521 NSEventTypeDirectTouch API_AVAILABLE(macos(10.10)) = 37,
7522
7523 NSEventTypeChangeMode API_AVAILABLE(macos(10.15)) = 38,
7524 };
7525
7526 typedef NS_ENUM(unsigned long long, NSEventMask) { /* masks for the types of events */
7527 NSEventMaskLeftMouseDown = 1ULL << NSEventTypeLeftMouseDown,
7528 NSEventMaskLeftMouseUp = 1ULL << NSEventTypeLeftMouseUp,
7529 NSEventMaskRightMouseDown = 1ULL << NSEventTypeRightMouseDown,
7530 NSEventMaskRightMouseUp = 1ULL << NSEventTypeRightMouseUp,
7531 NSEventMaskMouseMoved = 1ULL << NSEventTypeMouseMoved,
7532 NSEventMaskLeftMouseDragged = 1ULL << NSEventTypeLeftMouseDragged,
7533 NSEventMaskRightMouseDragged = 1ULL << NSEventTypeRightMouseDragged,
7534 NSEventMaskMouseEntered = 1ULL << NSEventTypeMouseEntered,
7535 NSEventMaskMouseExited = 1ULL << NSEventTypeMouseExited,
7536 NSEventMaskKeyDown = 1ULL << NSEventTypeKeyDown,
7537 NSEventMaskKeyUp = 1ULL << NSEventTypeKeyUp,
7538 NSEventMaskFlagsChanged = 1ULL << NSEventTypeFlagsChanged,
7539 NSEventMaskAppKitDefined = 1ULL << NSEventTypeAppKitDefined,
7540 NSEventMaskSystemDefined = 1ULL << NSEventTypeSystemDefined,
7541 NSEventMaskApplicationDefined = 1ULL << NSEventTypeApplicationDefined,
7542 NSEventMaskPeriodic = 1ULL << NSEventTypePeriodic,
7543 NSEventMaskCursorUpdate = 1ULL << NSEventTypeCursorUpdate,
7544 NSEventMaskScrollWheel = 1ULL << NSEventTypeScrollWheel,
7545 NSEventMaskTabletPoint = 1ULL << NSEventTypeTabletPoint,
7546 NSEventMaskTabletProximity = 1ULL << NSEventTypeTabletProximity,
7547 NSEventMaskOtherMouseDown = 1ULL << NSEventTypeOtherMouseDown,
7548 NSEventMaskOtherMouseUp = 1ULL << NSEventTypeOtherMouseUp,
7549 NSEventMaskOtherMouseDragged = 1ULL << NSEventTypeOtherMouseDragged,
7550 /* The following event masks are available on some hardware on 10.5.2 and later */
7551 NSEventMaskGesture API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeGesture,
7552 NSEventMaskMagnify API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeMagnify,
7553 NSEventMaskSwipe API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeSwipe,
7554 NSEventMaskRotate API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeRotate,
7555 NSEventMaskBeginGesture API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeBeginGesture,
7556 NSEventMaskEndGesture API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeEndGesture,
7557
7558 /* Note: You can only use these event masks on 64 bit. In other words, you cannot setup a local, nor global, event monitor for these event types on 32 bit. Also, you cannot search the event queue for them (nextEventMatchingMask:...) on 32 bit.
7559 */
7560 NSEventMaskSmartMagnify API_AVAILABLE(macos(10.8)) = 1ULL << NSEventTypeSmartMagnify,
7561 NSEventMaskPressure API_AVAILABLE(macos(10.10.3)) = 1ULL << NSEventTypePressure,
7562 NSEventMaskDirectTouch API_AVAILABLE(macos(10.12.2)) = 1ULL << NSEventTypeDirectTouch,
7563
7564 NSEventMaskChangeMode API_AVAILABLE(macos(10.15)) = 1ULL << NSEventTypeChangeMode,
7565
7566 NSEventMaskAny = ULONG_MAX,
7567
7568 };
7569
7570 typedef enum NSEventModifierFlags {
7571 NSEventModifierFlagCapsLock = 1 << 16,
7572 NSEventModifierFlagShift = 1 << 17,
7573 NSEventModifierFlagControl = 1 << 18,
7574 NSEventModifierFlagOption = 1 << 19,
7575 NSEventModifierFlagCommand = 1 << 20,
7576 NSEventModifierFlagNumericPad = 1 << 21
7577 } NSEventModifierFlags;
7578
7579 void RGFW_stopCheckEvents(void) {
7580 id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
7581 eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
7582
7583 NSEvent* e = (NSEvent*) ((id(*)(id, SEL, NSEventType, NSPoint, NSEventModifierFlags, void*, NSInteger, void**, short, NSInteger, NSInteger))objc_msgSend)
7584 (NSApp, sel_registerName("otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:"),
7585 NSEventTypeApplicationDefined, (NSPoint){0, 0}, 0, 0, 0, NULL, 0, 0, 0);
7586
7587 ((void (*)(id, SEL, id, bool))objc_msgSend)
7588 (NSApp, sel_registerName("postEvent:atStart:"), e, 1);
7589
7590 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
7591 }
7592
7593 void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) {
7594 RGFW_UNUSED(win);
7595
7596 id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
7597 eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
7598
7599 void* date = (void*) ((id(*)(Class, SEL, double))objc_msgSend)
7600 (objc_getClass("NSDate"), sel_registerName("dateWithTimeIntervalSinceNow:"), waitMS);
7601
7602 NSEvent* e = (NSEvent*) ((id(*)(id, SEL, NSEventMask, void*, NSString*, bool))objc_msgSend)
7603 (NSApp, sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"),
7604 ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true);
7605
7606
7607 if (e) {
7608 objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e);
7609 }
7610
7611 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
7612 }
7613
7614 RGFW_Event* RGFW_window_checkEvent(RGFW_window* win) {
7615 assert(win != NULL);
7616
7617 if (win->event.type == RGFW_quit)
7618 return NULL;
7619
7620 if ((win->event.type == RGFW_dnd || win->event.type == RGFW_dnd_init) && win->src.dndPassed == 0) {
7621 win->src.dndPassed = 1;
7622 return &win->event;
7623 }
7624
7625 id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc"));
7626 eventPool = objc_msgSend_id(eventPool, sel_registerName("init"));
7627
7628 static void* eventFunc = NULL;
7629 if (eventFunc == NULL)
7630 eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:");
7631
7632 if ((win->event.type == RGFW_windowMoved || win->event.type == RGFW_windowResized || win->event.type == RGFW_windowRefresh) && win->event.keyCode != 120) {
7633 win->event.keyCode = 120;
7634 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
7635 return &win->event;
7636 }
7637
7638 void* date = NULL;
7639
7640 NSEvent* e = (NSEvent*) ((id(*)(id, SEL, NSEventMask, void*, NSString*, bool))objc_msgSend)
7641 (NSApp, eventFunc, ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true);
7642
7643 if (e == NULL) {
7644 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
7645 return NULL;
7646 }
7647
7648 if (objc_msgSend_id(e, sel_registerName("window")) != win->src.window) {
7649 ((void (*)(id, SEL, id, bool))objc_msgSend)
7650 (NSApp, sel_registerName("postEvent:atStart:"), e, 0);
7651
7652 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
7653 return NULL;
7654 }
7655
7656 if (win->event.droppedFilesCount) {
7657 u32 i;
7658 for (i = 0; i < win->event.droppedFilesCount; i++)
7659 win->event.droppedFiles[i][0] = '\0';
7660 }
7661
7662 win->event.droppedFilesCount = 0;
7663 win->event.type = 0;
7664
7665 switch (objc_msgSend_uint(e, sel_registerName("type"))) {
7666 case NSEventTypeMouseEntered: {
7667 win->event.type = RGFW_mouseEnter;
7668 NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow"));
7669
7670 win->event.point = RGFW_POINT((i32) p.x, (i32) (win->r.h - p.y));
7671 RGFW_mouseNotifyCallBack(win, win->event.point, 1);
7672 break;
7673 }
7674
7675 case NSEventTypeMouseExited:
7676 win->event.type = RGFW_mouseLeave;
7677 RGFW_mouseNotifyCallBack(win, win->event.point, 0);
7678 break;
7679
7680 case NSEventTypeKeyDown: {
7681 u32 key = (u16) objc_msgSend_uint(e, sel_registerName("keyCode"));
7682 win->event.keyCode = RGFW_apiKeyCodeToRGFW(key);
7683 RGFW_keyboard[win->event.keyCode].prev = RGFW_keyboard[win->event.keyCode].current;
7684
7685 win->event.type = RGFW_keyPressed;
7686 char* str = (char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("characters")));
7687 strncpy(win->event.keyName, str, 16);
7688 win->event.repeat = RGFW_isPressed(win, win->event.keyCode);
7689 RGFW_keyboard[win->event.keyCode].current = 1;
7690
7691 RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, 1);
7692 break;
7693 }
7694
7695 case NSEventTypeKeyUp: {
7696 u32 key = (u16) objc_msgSend_uint(e, sel_registerName("keyCode"));
7697 win->event.keyCode = RGFW_apiKeyCodeToRGFW(key);;
7698
7699 RGFW_keyboard[win->event.keyCode].prev = RGFW_keyboard[win->event.keyCode].current;
7700
7701 win->event.type = RGFW_keyReleased;
7702 char* str = (char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("characters")));
7703 strncpy(win->event.keyName, str, 16);
7704
7705 RGFW_keyboard[win->event.keyCode].current = 0;
7706 RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, 0);
7707 break;
7708 }
7709
7710 case NSEventTypeFlagsChanged: {
7711 u32 flags = objc_msgSend_uint(e, sel_registerName("modifierFlags"));
7712 RGFW_updateLockState(win, ((u32)(flags & NSEventModifierFlagCapsLock) % 255), ((flags & NSEventModifierFlagNumericPad) % 255));
7713
7714 u8 i;
7715 for (i = 0; i < 9; i++)
7716 RGFW_keyboard[i + RGFW_CapsLock].prev = 0;
7717
7718 for (i = 0; i < 5; i++) {
7719 u32 shift = (1 << (i + 16));
7720 u32 key = i + RGFW_CapsLock;
7721
7722 if ((flags & shift) && !RGFW_wasPressed(win, key)) {
7723 RGFW_keyboard[key].current = 1;
7724
7725 if (key != RGFW_CapsLock)
7726 RGFW_keyboard[key+ 4].current = 1;
7727
7728 win->event.type = RGFW_keyPressed;
7729 win->event.keyCode = key;
7730 break;
7731 }
7732
7733 if (!(flags & shift) && RGFW_wasPressed(win, key)) {
7734 RGFW_keyboard[key].current = 0;
7735
7736 if (key != RGFW_CapsLock)
7737 RGFW_keyboard[key + 4].current = 0;
7738
7739 win->event.type = RGFW_keyReleased;
7740 win->event.keyCode = key;
7741 break;
7742 }
7743 }
7744
7745 RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, win->event.type == RGFW_keyPressed);
7746
7747 break;
7748 }
7749 case NSEventTypeLeftMouseDragged:
7750 case NSEventTypeOtherMouseDragged:
7751 case NSEventTypeRightMouseDragged:
7752 case NSEventTypeMouseMoved:
7753 win->event.type = RGFW_mousePosChanged;
7754 NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow"));
7755 win->event.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y));
7756
7757 if ((win->_winArgs & RGFW_HOLD_MOUSE)) {
7758 p.x = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaX"));
7759 p.y = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaY"));
7760
7761 win->event.point = RGFW_POINT((i32)p.x, (i32)p.y);
7762 }
7763
7764 RGFW_mousePosCallback(win, win->event.point);
7765 break;
7766
7767 case NSEventTypeLeftMouseDown:
7768 win->event.button = RGFW_mouseLeft;
7769 win->event.type = RGFW_mouseButtonPressed;
7770 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
7771 RGFW_mouseButtons[win->event.button].current = 1;
7772 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
7773 break;
7774
7775 case NSEventTypeOtherMouseDown:
7776 win->event.button = RGFW_mouseMiddle;
7777 win->event.type = RGFW_mouseButtonPressed;
7778 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
7779 RGFW_mouseButtons[win->event.button].current = 1;
7780 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
7781 break;
7782
7783 case NSEventTypeRightMouseDown:
7784 win->event.button = RGFW_mouseRight;
7785 win->event.type = RGFW_mouseButtonPressed;
7786 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
7787 RGFW_mouseButtons[win->event.button].current = 1;
7788 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
7789 break;
7790
7791 case NSEventTypeLeftMouseUp:
7792 win->event.button = RGFW_mouseLeft;
7793 win->event.type = RGFW_mouseButtonReleased;
7794 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
7795 RGFW_mouseButtons[win->event.button].current = 0;
7796 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0);
7797 break;
7798
7799 case NSEventTypeOtherMouseUp:
7800 win->event.button = RGFW_mouseMiddle;
7801 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
7802 RGFW_mouseButtons[win->event.button].current = 0;
7803 win->event.type = RGFW_mouseButtonReleased;
7804 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0);
7805 break;
7806
7807 case NSEventTypeRightMouseUp:
7808 win->event.button = RGFW_mouseRight;
7809 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
7810 RGFW_mouseButtons[win->event.button].current = 0;
7811 win->event.type = RGFW_mouseButtonReleased;
7812 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0);
7813 break;
7814
7815 case NSEventTypeScrollWheel: {
7816 double deltaY = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaY"));
7817
7818 if (deltaY > 0) {
7819 win->event.button = RGFW_mouseScrollUp;
7820 }
7821 else if (deltaY < 0) {
7822 win->event.button = RGFW_mouseScrollDown;
7823 }
7824
7825 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current;
7826 RGFW_mouseButtons[win->event.button].current = 1;
7827
7828 win->event.scroll = deltaY;
7829
7830 win->event.type = RGFW_mouseButtonPressed;
7831 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1);
7832 break;
7833 }
7834
7835 default:
7836 break;
7837 }
7838
7839 objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e);
7840 ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows"));
7841
7842 objc_msgSend_bool_void(eventPool, sel_registerName("drain"));
7843 return &win->event;
7844 }
7845
7846
7847 void RGFW_window_move(RGFW_window* win, RGFW_point v) {
7848 assert(win != NULL);
7849
7850 win->r.x = v.x;
7851 win->r.y = v.y;
7852 ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend)
7853 (win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h}}, true, true);
7854 }
7855
7856 void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
7857 assert(win != NULL);
7858
7859 win->r.w = a.w;
7860 win->r.h = a.h;
7861 ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend)
7862 (win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h}}, true, true);
7863 }
7864
7865 void RGFW_window_minimize(RGFW_window* win) {
7866 assert(win != NULL);
7867
7868 objc_msgSend_void_SEL(win->src.window, sel_registerName("performMiniaturize:"), NULL);
7869 }
7870
7871 void RGFW_window_restore(RGFW_window* win) {
7872 assert(win != NULL);
7873
7874 objc_msgSend_void_SEL(win->src.window, sel_registerName("deminiaturize:"), NULL);
7875 }
7876
7877 void RGFW_window_setName(RGFW_window* win, char* name) {
7878 assert(win != NULL);
7879
7880 NSString* str = NSString_stringWithUTF8String(name);
7881 objc_msgSend_void_id(win->src.window, sel_registerName("setTitle:"), str);
7882 }
7883
7884 #ifndef RGFW_NO_PASSTHROUGH
7885 void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) {
7886 objc_msgSend_void_bool(win->src.window, sel_registerName("setIgnoresMouseEvents:"), passthrough);
7887 }
7888 #endif
7889
7890 void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) {
7891 if (a.w == 0 && a.h == 0)
7892 return;
7893
7894 ((void (*)(id, SEL, NSSize))objc_msgSend)
7895 (win->src.window, sel_registerName("setMinSize:"), (NSSize){a.w, a.h});
7896 }
7897
7898 void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) {
7899 if (a.w == 0 && a.h == 0)
7900 return;
7901
7902 ((void (*)(id, SEL, NSSize))objc_msgSend)
7903 (win->src.window, sel_registerName("setMaxSize:"), (NSSize){a.w, a.h});
7904 }
7905
7906 void RGFW_window_setIcon(RGFW_window* win, u8* data, RGFW_area area, i32 channels) {
7907 assert(win != NULL);
7908
7909 /* code by EimaMei */
7910 // Make a bitmap representation, then copy the loaded image into it.
7911 void* representation = NSBitmapImageRep_initWithBitmapData(NULL, area.w, area.h, 8, channels, (channels == 4), false, "NSCalibratedRGBColorSpace", 1 << 1, area.w * channels, 8 * channels);
7912 memcpy(NSBitmapImageRep_bitmapData(representation), data, area.w * area.h * channels);
7913
7914 // Add ze representation.
7915 void* dock_image = NSImage_initWithSize((NSSize){area.w, area.h});
7916 NSImage_addRepresentation(dock_image, (void*) representation);
7917
7918 // Finally, set the dock image to it.
7919 objc_msgSend_void_id(NSApp, sel_registerName("setApplicationIconImage:"), dock_image);
7920 // Free the garbage.
7921 release(dock_image);
7922 release(representation);
7923 }
7924
7925 NSCursor* NSCursor_arrowStr(char* str) {
7926 void* nclass = objc_getClass("NSCursor");
7927 void* func = sel_registerName(str);
7928 return (NSCursor*) objc_msgSend_id(nclass, func);
7929 }
7930
7931 void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels) {
7932 assert(win != NULL);
7933
7934 if (image == NULL) {
7935 objc_msgSend_void(NSCursor_arrowStr("arrowCursor"), sel_registerName("set"));
7936 return;
7937 }
7938
7939 /* NOTE(EimaMei): Code by yours truly. */
7940 // Make a bitmap representation, then copy the loaded image into it.
7941 void* representation = NSBitmapImageRep_initWithBitmapData(NULL, a.w, a.h, 8, channels, (channels == 4), false, "NSCalibratedRGBColorSpace", 1 << 1, a.w * channels, 8 * channels);
7942 memcpy(NSBitmapImageRep_bitmapData(representation), image, a.w * a.h * channels);
7943
7944 // Add ze representation.
7945 void* cursor_image = NSImage_initWithSize((NSSize){a.w, a.h});
7946 NSImage_addRepresentation(cursor_image, representation);
7947
7948 // Finally, set the cursor image.
7949 void* cursor = NSCursor_initWithImage(cursor_image, (NSPoint){0.0, 0.0});
7950
7951 objc_msgSend_void(cursor, sel_registerName("set"));
7952
7953 // Free the garbage.
7954 release(cursor_image);
7955 release(representation);
7956 }
7957
7958 void RGFW_window_setMouseDefault(RGFW_window* win) {
7959 RGFW_window_setMouseStandard(win, RGFW_MOUSE_ARROW);
7960 }
7961
7962 void RGFW_window_showMouse(RGFW_window* win, i8 show) {
7963 RGFW_UNUSED(win);
7964
7965 if (show) {
7966 CGDisplayShowCursor(kCGDirectMainDisplay);
7967 }
7968 else {
7969 CGDisplayHideCursor(kCGDirectMainDisplay);
7970 }
7971 }
7972
7973 void RGFW_window_setMouseStandard(RGFW_window* win, u8 stdMouses) {
7974 if (stdMouses > ((sizeof(RGFW_mouseIconSrc)) / (sizeof(char*))))
7975 return;
7976
7977 char* mouseStr = RGFW_mouseIconSrc[stdMouses];
7978 void* mouse = NSCursor_arrowStr(mouseStr);
7979
7980 if (mouse == NULL)
7981 return;
7982
7983 RGFW_UNUSED(win);
7984 CGDisplayShowCursor(kCGDirectMainDisplay);
7985 objc_msgSend_void(mouse, sel_registerName("set"));
7986 }
7987
7988 void RGFW_releaseCursor(RGFW_window* win) {
7989 RGFW_UNUSED(win);
7990 CGAssociateMouseAndMouseCursorPosition(1);
7991 }
7992
7993 void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) {
7994 RGFW_UNUSED(win)
7995
7996 CGWarpMouseCursorPosition(CGPointMake(r.x + (r.w / 2), r.y + (r.h / 2)));
7997 CGAssociateMouseAndMouseCursorPosition(0);
7998 }
7999
8000 void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) {
8001 RGFW_UNUSED(win);
8002
8003 CGWarpMouseCursorPosition(CGPointMake(v.x, v.y));
8004 }
8005
8006
8007 void RGFW_window_hide(RGFW_window* win) {
8008 objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), false);
8009 }
8010
8011 void RGFW_window_show(RGFW_window* win) {
8012 ((id(*)(id, SEL, SEL))objc_msgSend)(win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL);
8013 objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), true);
8014 }
8015
8016 u8 RGFW_window_isFullscreen(RGFW_window* win) {
8017 assert(win != NULL);
8018
8019 NSWindowStyleMask mask = (NSWindowStyleMask) objc_msgSend_uint(win->src.window, sel_registerName("styleMask"));
8020 return (mask & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen;
8021 }
8022
8023 u8 RGFW_window_isHidden(RGFW_window* win) {
8024 assert(win != NULL);
8025
8026 bool visible = objc_msgSend_bool(win->src.window, sel_registerName("isVisible"));
8027 return visible == NO && !RGFW_window_isMinimized(win);
8028 }
8029
8030 u8 RGFW_window_isMinimized(RGFW_window* win) {
8031 assert(win != NULL);
8032
8033 return objc_msgSend_bool(win->src.window, sel_registerName("isMiniaturized")) == YES;
8034 }
8035
8036 u8 RGFW_window_isMaximized(RGFW_window* win) {
8037 assert(win != NULL);
8038
8039 return objc_msgSend_bool(win->src.window, sel_registerName("isZoomed"));
8040 }
8041
8042 static RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display) {
8043 RGFW_monitor monitor;
8044
8045 CGRect bounds = CGDisplayBounds(display);
8046 monitor.rect = RGFW_RECT((int) bounds.origin.x, (int) bounds.origin.y, (int) bounds.size.width, (int) bounds.size.height);
8047
8048 CGSize screenSizeMM = CGDisplayScreenSize(display);
8049 monitor.physW = screenSizeMM.width;
8050 monitor.physH = screenSizeMM.height;
8051
8052 monitor.scaleX = ((monitor.rect.w / (screenSizeMM.width / 25.4)) / 96) + 0.25;
8053 monitor.scaleY = ((monitor.rect.h / (screenSizeMM.height / 25.4)) / 96) + 0.25;
8054
8055 return monitor;
8056 }
8057
8058
8059 static RGFW_monitor RGFW_monitors[7];
8060
8061 RGFW_monitor* RGFW_getMonitors(void) {
8062 static CGDirectDisplayID displays[7];
8063 u32 count;
8064
8065 if (CGGetActiveDisplayList(6, displays, &count) != kCGErrorSuccess)
8066 return NULL;
8067
8068 for (u32 i = 0; i < count; i++)
8069 RGFW_monitors[i] = RGFW_NSCreateMonitor(displays[i]);
8070
8071 return RGFW_monitors;
8072 }
8073
8074 RGFW_monitor RGFW_getPrimaryMonitor(void) {
8075 CGDirectDisplayID primary = CGMainDisplayID();
8076 return RGFW_NSCreateMonitor(primary);
8077 }
8078
8079 RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) {
8080 return RGFW_NSCreateMonitor(win->src.display);
8081 }
8082
8083 char* RGFW_readClipboard(size_t* size) {
8084 char* clip = (char*)NSPasteboard_stringForType(NSPasteboard_generalPasteboard(), NSPasteboardTypeString);
8085
8086 size_t clip_len = 1;
8087
8088 if (clip != NULL) {
8089 clip_len = strlen(clip) + 1;
8090 }
8091
8092 char* str = (char*)RGFW_MALLOC(sizeof(char) * clip_len);
8093
8094 if (clip != NULL) {
8095 strncpy(str, clip, clip_len);
8096 }
8097
8098 str[clip_len] = '\0';
8099
8100 if (size != NULL)
8101 *size = clip_len;
8102 return str;
8103 }
8104
8105 void RGFW_writeClipboard(const char* text, u32 textLen) {
8106 RGFW_UNUSED(textLen);
8107
8108 NSPasteboardType array[] = { NSPasteboardTypeString, NULL };
8109 NSPasteBoard_declareTypes(NSPasteboard_generalPasteboard(), array, 1, NULL);
8110
8111 NSPasteBoard_setString(NSPasteboard_generalPasteboard(), text, NSPasteboardTypeString);
8112 }
8113
8114 u16 RGFW_registerJoystick(RGFW_window* win, i32 jsNumber) {
8115 RGFW_UNUSED(jsNumber);
8116
8117 assert(win != NULL);
8118
8119 return RGFW_registerJoystickF(win, (char*) "");
8120 }
8121
8122 u16 RGFW_registerJoystickF(RGFW_window* win, char* file) {
8123 RGFW_UNUSED(file);
8124
8125 assert(win != NULL);
8126
8127 return RGFW_joystickCount - 1;
8128 }
8129
8130 #ifdef RGFW_OPENGL
8131 void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
8132 assert(win != NULL);
8133 objc_msgSend_void(win->src.ctx, sel_registerName("makeCurrentContext"));
8134 }
8135 #endif
8136
8137 #if !defined(RGFW_EGL)
8138 void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) {
8139 assert(win != NULL);
8140 #if defined(RGFW_OPENGL)
8141
8142 NSOpenGLContext_setValues(win->src.ctx, &swapInterval, 222);
8143 #else
8144 RGFW_UNUSED(swapInterval);
8145 #endif
8146 }
8147 #endif
8148
8149 // Function to create a CGImageRef from an array of bytes
8150 CGImageRef createImageFromBytes(unsigned char *buffer, int width, int height)
8151 {
8152 // Define color space
8153 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
8154 // Create bitmap context
8155 CGContextRef context = CGBitmapContextCreate(
8156 buffer,
8157 width, height,
8158 8,
8159 RGFW_bufferSize.w * 4,
8160 colorSpace,
8161 kCGImageAlphaPremultipliedLast);
8162 // Create image from bitmap context
8163 CGImageRef image = CGBitmapContextCreateImage(context);
8164 // Release the color space and context
8165 CGColorSpaceRelease(colorSpace);
8166 CGContextRelease(context);
8167
8168 return image;
8169 }
8170
8171 void RGFW_window_swapBuffers(RGFW_window* win) {
8172 assert(win != NULL);
8173 /* clear the window*/
8174
8175 if (!(win->_winArgs & RGFW_NO_CPU_RENDER)) {
8176#if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
8177 #ifdef RGFW_OSMESA
8178 RGFW_OSMesa_reorganize();
8179 #endif
8180
8181 void* view = NSWindow_contentView(win->src.window);
8182 void* layer = objc_msgSend_id(view, sel_registerName("layer"));
8183
8184 ((void(*)(id, SEL, NSRect))objc_msgSend)(layer,
8185 sel_registerName("setFrame:"),
8186 (NSRect){{0, 0}, {win->r.w, win->r.h}});
8187
8188 CGImageRef image = createImageFromBytes(win->buffer, win->r.w, win->r.h);
8189 // Get the current graphics context
8190 id graphicsContext = objc_msgSend_class(objc_getClass("NSGraphicsContext"), sel_registerName("currentContext"));
8191 // Get the CGContext from the current NSGraphicsContext
8192 id cgContext = objc_msgSend_id(graphicsContext, sel_registerName("graphicsPort"));
8193 // Draw the image in the context
8194 NSRect bounds = (NSRect){{0,0}, {win->r.w, win->r.h}};
8195 CGContextDrawImage((void*)cgContext, *(CGRect*)&bounds, image);
8196 // Flush the graphics context to ensure the drawing is displayed
8197 objc_msgSend_id(graphicsContext, sel_registerName("flushGraphics"));
8198
8199 objc_msgSend_void_id(layer, sel_registerName("setContents:"), (id)image);
8200 objc_msgSend_id(layer, sel_registerName("setNeedsDisplay"));
8201
8202 CGImageRelease(image);
8203#endif
8204 }
8205
8206 if (!(win->_winArgs & RGFW_NO_GPU_RENDER)) {
8207 #ifdef RGFW_EGL
8208 eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface);
8209 #elif defined(RGFW_OPENGL)
8210 objc_msgSend_void(win->src.ctx, sel_registerName("flushBuffer"));
8211 #endif
8212 }
8213 }
8214
8215 void RGFW_window_close(RGFW_window* win) {
8216 assert(win != NULL);
8217 release(win->src.view);
8218
8219#ifdef RGFW_ALLOC_DROPFILES
8220 {
8221 u32 i;
8222 for (i = 0; i < RGFW_MAX_DROPS; i++)
8223 RGFW_FREE(win->event.droppedFiles[i]);
8224
8225
8226 RGFW_FREE(win->event.droppedFiles);
8227 }
8228#endif
8229
8230#ifdef RGFW_BUFFER
8231 release(win->src.bitmap);
8232 release(win->src.image);
8233#endif
8234
8235 CVDisplayLinkStop(win->src.displayLink);
8236 CVDisplayLinkRelease(win->src.displayLink);
8237
8238 RGFW_FREE(win);
8239 }
8240
8241 u64 RGFW_getTimeNS(void) {
8242 static mach_timebase_info_data_t timebase_info;
8243 if (timebase_info.denom == 0) {
8244 mach_timebase_info(&timebase_info);
8245 }
8246 return mach_absolute_time() * timebase_info.numer / timebase_info.denom;
8247 }
8248
8249 u64 RGFW_getTime(void) {
8250 static mach_timebase_info_data_t timebase_info;
8251 if (timebase_info.denom == 0) {
8252 mach_timebase_info(&timebase_info);
8253 }
8254 return (double) mach_absolute_time() * (double) timebase_info.numer / ((double) timebase_info.denom * 1e9);
8255 }
8256#endif /* RGFW_MACOS */
8257
8258/*
8259 End of MaOS defines
8260*/
8261
8262/*
8263 WEBASM defines
8264*/
8265
8266#ifdef RGFW_WEBASM
8267RGFW_Event RGFW_events[20];
8268size_t RGFW_eventLen = 0;
8269
8270EM_BOOL Emscripten_on_keydown(int eventType, const EmscriptenKeyboardEvent* e, void* userData) {
8271 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
8272
8273 RGFW_events[RGFW_eventLen].type = RGFW_keyPressed;
8274 memcpy(RGFW_events[RGFW_eventLen].keyName, e->key, 16);
8275 RGFW_events[RGFW_eventLen].keyCode = RGFW_apiKeyCodeToRGFW(e->keyCode);
8276 RGFW_events[RGFW_eventLen].lockState = 0;
8277 RGFW_eventLen++;
8278
8279 RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].prev = RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].current;
8280 RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].current = 1;
8281 RGFW_keyCallback(RGFW_root, RGFW_apiKeyCodeToRGFW(e->keyCode), RGFW_events[RGFW_eventLen].keyName, 0, 1);
8282
8283 return EM_TRUE;
8284}
8285
8286EM_BOOL Emscripten_on_keyup(int eventType, const EmscriptenKeyboardEvent* e, void* userData) {
8287 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
8288
8289 RGFW_events[RGFW_eventLen].type = RGFW_keyReleased;
8290 memcpy(RGFW_events[RGFW_eventLen].keyName, e->key, 16);
8291 RGFW_events[RGFW_eventLen].keyCode = RGFW_apiKeyCodeToRGFW(e->keyCode);
8292 RGFW_events[RGFW_eventLen].lockState = 0;
8293 RGFW_eventLen++;
8294
8295 RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].prev = RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].current;
8296 RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].current = 0;
8297
8298 RGFW_keyCallback(RGFW_root, RGFW_apiKeyCodeToRGFW(e->keyCode), RGFW_events[RGFW_eventLen].keyName, 0, 0);
8299
8300 return EM_TRUE;
8301}
8302
8303EM_BOOL Emscripten_on_resize(int eventType, const EmscriptenUiEvent* e, void* userData) {
8304 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
8305
8306 RGFW_events[RGFW_eventLen].type = RGFW_windowResized;
8307 RGFW_eventLen++;
8308
8309 RGFW_windowResizeCallback(RGFW_root, RGFW_RECT(0, 0, e->windowInnerWidth, e->windowInnerHeight));
8310 return EM_TRUE;
8311}
8312
8313EM_BOOL Emscripten_on_fullscreenchange(int eventType, const EmscriptenFullscreenChangeEvent* e, void* userData) {
8314 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
8315
8316 RGFW_events[RGFW_eventLen].type = RGFW_windowResized;
8317 RGFW_eventLen++;
8318
8319 RGFW_root->r = RGFW_RECT(0, 0, e->elementWidth, e->elementHeight);
8320 RGFW_windowResizeCallback(RGFW_root, RGFW_root->r);
8321 return EM_TRUE;
8322}
8323
8324EM_BOOL Emscripten_on_focusin(int eventType, const EmscriptenFocusEvent* e, void* userData) {
8325 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(e);
8326
8327 RGFW_events[RGFW_eventLen].type = RGFW_focusIn;
8328 RGFW_eventLen++;
8329
8330 RGFW_root->event.inFocus = 1;
8331 RGFW_focusCallback(RGFW_root, 1);
8332 return EM_TRUE;
8333}
8334
8335EM_BOOL Emscripten_on_focusout(int eventType, const EmscriptenFocusEvent* e, void* userData) {
8336 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(e);
8337
8338 RGFW_events[RGFW_eventLen].type = RGFW_focusOut;
8339 RGFW_eventLen++;
8340
8341 RGFW_root->event.inFocus = 0;
8342 RGFW_focusCallback(RGFW_root, 0);
8343 return EM_TRUE;
8344}
8345
8346EM_BOOL Emscripten_on_mousemove(int eventType, const EmscriptenMouseEvent* e, void* userData) {
8347 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
8348
8349 RGFW_events[RGFW_eventLen].type = RGFW_mousePosChanged;
8350
8351 if ((RGFW_root->_winArgs & RGFW_HOLD_MOUSE)) {
8352 RGFW_point p = RGFW_POINT(e->movementX, e->movementY);
8353 RGFW_events[RGFW_eventLen].point = p;
8354 }
8355 else
8356 RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->targetX, e->targetY);
8357 RGFW_eventLen++;
8358
8359 RGFW_mousePosCallback(RGFW_root, RGFW_events[RGFW_eventLen].point);
8360 return EM_TRUE;
8361}
8362
8363EM_BOOL Emscripten_on_mousedown(int eventType, const EmscriptenMouseEvent* e, void* userData) {
8364 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
8365
8366 RGFW_events[RGFW_eventLen].type = RGFW_mouseButtonPressed;
8367 RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->targetX, e->targetY);
8368 RGFW_events[RGFW_eventLen].button = e->button + 1;
8369 RGFW_events[RGFW_eventLen].scroll = 0;
8370
8371 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].prev = RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current;
8372 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current = 1;
8373
8374 RGFW_mouseButtonCallback(RGFW_root, RGFW_events[RGFW_eventLen].button, RGFW_events[RGFW_eventLen].scroll, 1);
8375 RGFW_eventLen++;
8376
8377 return EM_TRUE;
8378}
8379
8380EM_BOOL Emscripten_on_mouseup(int eventType, const EmscriptenMouseEvent* e, void* userData) {
8381 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
8382
8383 RGFW_events[RGFW_eventLen].type = RGFW_mouseButtonReleased;
8384 RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->targetX, e->targetY);
8385 RGFW_events[RGFW_eventLen].button = e->button + 1;
8386 RGFW_events[RGFW_eventLen].scroll = 0;
8387
8388 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].prev = RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current;
8389 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current = 0;
8390
8391 RGFW_mouseButtonCallback(RGFW_root, RGFW_events[RGFW_eventLen].button, RGFW_events[RGFW_eventLen].scroll, 0);
8392 RGFW_eventLen++;
8393 return EM_TRUE;
8394}
8395
8396EM_BOOL Emscripten_on_wheel(int eventType, const EmscriptenWheelEvent* e, void* userData) {
8397 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
8398
8399 RGFW_events[RGFW_eventLen].type = RGFW_mouseButtonPressed;
8400 RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->mouse.targetX, e->mouse.targetY);
8401 RGFW_events[RGFW_eventLen].button = RGFW_mouseScrollUp + (e->deltaY < 0);
8402 RGFW_events[RGFW_eventLen].scroll = e->deltaY;
8403
8404 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].prev = RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current;
8405 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current = 1;
8406
8407 RGFW_mouseButtonCallback(RGFW_root, RGFW_events[RGFW_eventLen].button, RGFW_events[RGFW_eventLen].scroll, 1);
8408 RGFW_eventLen++;
8409
8410 return EM_TRUE;
8411}
8412
8413EM_BOOL Emscripten_on_touchstart(int eventType, const EmscriptenTouchEvent* e, void* userData) {
8414 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
8415
8416 size_t i;
8417 for (i = 0; i < (size_t)e->numTouches; i++) {
8418 RGFW_events[RGFW_eventLen].type = RGFW_mouseButtonPressed;
8419 RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->touches[i].targetX, e->touches[i].targetY);
8420 RGFW_events[RGFW_eventLen].button = 1;
8421 RGFW_events[RGFW_eventLen].scroll = 0;
8422
8423
8424 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].prev = RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current;
8425 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current = 1;
8426
8427 RGFW_mousePosCallback(RGFW_root, RGFW_events[RGFW_eventLen].point);
8428
8429 RGFW_mouseButtonCallback(RGFW_root, RGFW_events[RGFW_eventLen].button, RGFW_events[RGFW_eventLen].scroll, 1);
8430 RGFW_eventLen++;
8431 }
8432
8433 return EM_TRUE;
8434}
8435EM_BOOL Emscripten_on_touchmove(int eventType, const EmscriptenTouchEvent* e, void* userData) {
8436 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
8437
8438 size_t i;
8439 for (i = 0; i < (size_t)e->numTouches; i++) {
8440 RGFW_events[RGFW_eventLen].type = RGFW_mousePosChanged;
8441 RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->touches[i].targetX, e->touches[i].targetY);
8442
8443 RGFW_mousePosCallback(RGFW_root, RGFW_events[RGFW_eventLen].point);
8444 RGFW_eventLen++;
8445 }
8446 return EM_TRUE;
8447}
8448
8449EM_BOOL Emscripten_on_touchend(int eventType, const EmscriptenTouchEvent* e, void* userData) {
8450 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
8451
8452 size_t i;
8453 for (i = 0; i < (size_t)e->numTouches; i++) {
8454 RGFW_events[RGFW_eventLen].type = RGFW_mouseButtonReleased;
8455 RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->touches[i].targetX, e->touches[i].targetY);
8456 RGFW_events[RGFW_eventLen].button = 1;
8457 RGFW_events[RGFW_eventLen].scroll = 0;
8458
8459 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].prev = RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current;
8460 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current = 0;
8461
8462 RGFW_mouseButtonCallback(RGFW_root, RGFW_events[RGFW_eventLen].button, RGFW_events[RGFW_eventLen].scroll, 0);
8463 RGFW_eventLen++;
8464 }
8465 return EM_TRUE;
8466}
8467
8468EM_BOOL Emscripten_on_touchcancel(int eventType, const EmscriptenTouchEvent* e, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(e); return EM_TRUE; }
8469
8470EM_BOOL Emscripten_on_gamepad(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData) {
8471 RGFW_UNUSED(eventType); RGFW_UNUSED(userData);
8472
8473 if (gamepadEvent->index >= 4)
8474 return 0;
8475
8476 RGFW_joysticks[gamepadEvent->index] = gamepadEvent->connected;
8477
8478 return 1; // The event was consumed by the callback handler
8479}
8480
8481void EMSCRIPTEN_KEEPALIVE Emscripten_onDrop(size_t count) {
8482 if (!(RGFW_root->_winArgs & RGFW_ALLOW_DND))
8483 return;
8484
8485 RGFW_events[RGFW_eventLen].droppedFilesCount = count;
8486 RGFW_dndCallback(RGFW_root, RGFW_events[RGFW_eventLen].droppedFiles, count);
8487 RGFW_eventLen++;
8488}
8489
8490b8 RGFW_stopCheckEvents_bool = RGFW_FALSE;
8491void RGFW_stopCheckEvents(void) {
8492 RGFW_stopCheckEvents_bool = RGFW_TRUE;
8493}
8494
8495void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) {
8496 RGFW_UNUSED(win);
8497
8498 if (waitMS == 0)
8499 return;
8500
8501 u32 start = (u32)(((u64)RGFW_getTimeNS()) / 1e+6);
8502
8503 while ((RGFW_eventLen == 0) && RGFW_stopCheckEvents_bool == RGFW_FALSE &&
8504 (waitMS < 0 || (RGFW_getTimeNS() / 1e+6) - start < waitMS)
8505 ) {
8506 emscripten_sleep(0);
8507 }
8508
8509 RGFW_stopCheckEvents_bool = RGFW_FALSE;
8510}
8511
8512RGFWDEF void RGFW_init_buffer(RGFW_window* win);
8513void RGFW_init_buffer(RGFW_window* win) {
8514 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER)
8515 if (RGFW_bufferSize.w == 0 && RGFW_bufferSize.h == 0)
8516 RGFW_bufferSize = RGFW_getScreenSize();
8517
8518 win->buffer = RGFW_MALLOC(RGFW_bufferSize.w * RGFW_bufferSize.h * 4);
8519 #ifdef RGFW_OSMESA
8520 win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL);
8521 OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, win->r.w, win->r.h);
8522 #endif
8523 #else
8524 RGFW_UNUSED(win); /*!< if buffer rendering is not being used */
8525 #endif
8526}
8527
8528void EMSCRIPTEN_KEEPALIVE RGFW_makeSetValue(size_t index, char* file) {
8529 /* This seems like a terrible idea, don't replicate this unless you hate yourself or the OS */
8530 /* TODO: find a better way to do this,
8531 strcpy doesn't seem to work, maybe because of asyncio
8532 */
8533
8534 RGFW_events[RGFW_eventLen].type = RGFW_dnd;
8535 char** arr = (char**)&RGFW_events[RGFW_eventLen].droppedFiles[index];
8536 *arr = file;
8537}
8538
8539#include <sys/stat.h>
8540#include <sys/types.h>
8541#include <errno.h>
8542
8543void EMSCRIPTEN_KEEPALIVE RGFW_mkdir(char* name) { mkdir(name, 0755); }
8544
8545void EMSCRIPTEN_KEEPALIVE RGFW_writeFile(const char *path, const char *data, size_t len) {
8546 FILE* file = fopen(path, "w+");
8547 if (file == NULL)
8548 return;
8549
8550 fwrite(data, sizeof(char), len, file);
8551 fclose(file);
8552}
8553
8554RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) {
8555 RGFW_UNUSED(name)
8556
8557 RGFW_UNUSED(RGFW_initFormatAttribs);
8558
8559 RGFW_window* win = RGFW_window_basic_init(rect, args);
8560
8561#ifndef RGFW_WEBGPU
8562 EmscriptenWebGLContextAttributes attrs;
8563 attrs.alpha = EM_TRUE;
8564 attrs.depth = EM_TRUE;
8565 attrs.alpha = EM_TRUE;
8566 attrs.stencil = RGFW_STENCIL;
8567 attrs.antialias = RGFW_SAMPLES;
8568 attrs.premultipliedAlpha = EM_TRUE;
8569 attrs.preserveDrawingBuffer = EM_FALSE;
8570
8571 if (RGFW_DOUBLE_BUFFER == 0)
8572 attrs.renderViaOffscreenBackBuffer = 0;
8573 else
8574 attrs.renderViaOffscreenBackBuffer = RGFW_AUX_BUFFERS;
8575
8576 attrs.failIfMajorPerformanceCaveat = EM_FALSE;
8577 attrs.majorVersion = (RGFW_majorVersion == 0) ? 1 : RGFW_majorVersion;
8578 attrs.minorVersion = RGFW_minorVersion;
8579
8580 attrs.enableExtensionsByDefault = EM_TRUE;
8581 attrs.explicitSwapControl = EM_TRUE;
8582
8583 emscripten_webgl_init_context_attributes(&attrs);
8584 win->src.ctx = emscripten_webgl_create_context("#canvas", &attrs);
8585 emscripten_webgl_make_context_current(win->src.ctx);
8586
8587 #ifdef LEGACY_GL_EMULATION
8588 EM_ASM("Module.useWebGL = true; GLImmediate.init();");
8589 #endif
8590#else
8591 win->src.ctx = wgpuCreateInstance(NULL);
8592 win->src.device = emscripten_webgpu_get_device();
8593 win->src.queue = wgpuDeviceGetQueue(win->src.device);
8594#endif
8595
8596 emscripten_set_canvas_element_size("#canvas", rect.w, rect.h);
8597 emscripten_set_window_title(name);
8598
8599 /* load callbacks */
8600 emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_keydown);
8601 emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_keyup);
8602 emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_resize);
8603 emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, NULL, EM_FALSE, Emscripten_on_fullscreenchange);
8604 emscripten_set_mousemove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousemove);
8605 emscripten_set_touchstart_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchstart);
8606 emscripten_set_touchend_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchend);
8607 emscripten_set_touchmove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchmove);
8608 emscripten_set_touchcancel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchcancel);
8609 emscripten_set_mousedown_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousedown);
8610 emscripten_set_mouseup_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mouseup);
8611 emscripten_set_wheel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_wheel);
8612 emscripten_set_focusin_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusin);
8613 emscripten_set_focusout_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusout);
8614 emscripten_set_gamepadconnected_callback(NULL, 1, Emscripten_on_gamepad);
8615 emscripten_set_gamepaddisconnected_callback(NULL, 1, Emscripten_on_gamepad);
8616
8617 if (args & RGFW_ALLOW_DND) {
8618 win->_winArgs |= RGFW_ALLOW_DND;
8619 }
8620
8621 EM_ASM({
8622 var canvas = document.getElementById('canvas');
8623 canvas.addEventListener('drop', function(e) {
8624 e.preventDefault();
8625 if (e.dataTransfer.file < 0)
8626 return;
8627
8628 var filenamesArray = [];
8629 var count = e.dataTransfer.files.length;
8630
8631 /* Read and save the files to emscripten's files */
8632 var drop_dir = '.rgfw_dropped_files';
8633 Module._RGFW_mkdir(drop_dir);
8634
8635 for (var i = 0; i < count; i++) {
8636 var file = e.dataTransfer.files[i];
8637
8638 var path = '/' + drop_dir + '/' + file.name.replace("//", '_');
8639 var reader = new FileReader();
8640
8641 reader.onloadend = (e) => {
8642 if (reader.readyState != 2) {
8643 out('failed to read dropped file: '+file.name+': '+reader.error);
8644 }
8645 else {
8646 var data = e.target.result;
8647
8648 _RGFW_writeFile(path, new Uint8Array(data), file.size);
8649 }
8650 };
8651
8652 reader.readAsArrayBuffer(file);
8653 // This works weird on modern opengl
8654 var filename = stringToNewUTF8(path);
8655
8656 filenamesArray.push(filename);
8657
8658 Module._RGFW_makeSetValue(i, filename);
8659 }
8660
8661 Module._Emscripten_onDrop(count);
8662
8663 for (var i = 0; i < count; ++i) {
8664 _free(filenamesArray[i]);
8665 }
8666 }, true);
8667
8668 canvas.addEventListener('dragover', function(e) { e.preventDefault(); return false; }, true);
8669 });
8670
8671 RGFW_init_buffer(win);
8672 glViewport(0, 0, rect.w, rect.h);
8673
8674 RGFW_root = win;
8675
8676 if (args & RGFW_HIDE_MOUSE) {
8677 RGFW_window_showMouse(win, 0);
8678 }
8679
8680 if (args & RGFW_FULLSCREEN) {
8681 RGFW_window_resize(win, RGFW_getScreenSize());
8682 }
8683
8684 return win;
8685}
8686
8687RGFW_Event* RGFW_window_checkEvent(RGFW_window* win) {
8688 static u8 index = 0;
8689
8690 if (index == 0)
8691 RGFW_resetKey();
8692
8693 /* check gamepads */
8694 for (int i = 0; (i < emscripten_get_num_gamepads()) && (i < 4); i++) {
8695 if (RGFW_joysticks[i] == 0)
8696 continue;;
8697
8698 EmscriptenGamepadEvent gamepadState;
8699
8700 if (emscripten_get_gamepad_status(i, &gamepadState) != EMSCRIPTEN_RESULT_SUCCESS)
8701 break;
8702
8703 // Register buttons data for every connected gamepad
8704 for (int j = 0; (j < gamepadState.numButtons) && (j < 16); j++) {
8705 u32 map[] = {
8706 RGFW_JS_A, RGFW_JS_X, RGFW_JS_B, RGFW_JS_Y,
8707 RGFW_JS_L1, RGFW_JS_R1, RGFW_JS_L2, RGFW_JS_R2,
8708 RGFW_JS_SELECT, RGFW_JS_START,
8709 0, 0,
8710 RGFW_JS_UP, RGFW_JS_DOWN, RGFW_JS_LEFT, RGFW_JS_RIGHT
8711 };
8712
8713 u32 button = map[j];
8714 if (RGFW_jsPressed[i][button] != gamepadState.digitalButton[j]) {
8715 win->event.type = RGFW_jsButtonPressed;
8716 win->event.joystick = i;
8717 win->event.button = map[j];
8718 return &win->event;
8719 }
8720
8721 RGFW_jsPressed[i][button] = gamepadState.digitalButton[j];
8722 }
8723
8724 for (int j = 0; (j < gamepadState.numAxes) && (j < 4); j += 2) {
8725 win->event.axisesCount = gamepadState.numAxes;
8726 if (win->event.axis[j].x != gamepadState.axis[j] ||
8727 win->event.axis[j].y != gamepadState.axis[j + 1]
8728 ) {
8729 win->event.axis[j].x = gamepadState.axis[j];
8730 win->event.axis[j].y = gamepadState.axis[j + 1];
8731 win->event.type = RGFW_jsAxisMove;
8732 win->event.joystick = i;
8733 return &win->event;
8734 }
8735 }
8736 }
8737
8738 /* check queued events */
8739 if (RGFW_eventLen == 0)
8740 return NULL;
8741
8742 RGFW_events[index].frameTime = win->event.frameTime;
8743 RGFW_events[index].frameTime2 = win->event.frameTime2;
8744 RGFW_events[index].inFocus = win->event.inFocus;
8745
8746 win->event = RGFW_events[index];
8747
8748 RGFW_eventLen--;
8749
8750 if (RGFW_eventLen)
8751 index++;
8752 else
8753 index = 0;
8754
8755 return &win->event;
8756}
8757
8758void RGFW_window_resize(RGFW_window* win, RGFW_area a) {
8759 RGFW_UNUSED(win)
8760 emscripten_set_canvas_element_size("#canvas", a.w, a.h);
8761}
8762
8763/* NOTE: I don't know if this is possible */
8764void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win); RGFW_UNUSED(v); }
8765/* this one might be possible but it looks iffy */
8766void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels) { RGFW_UNUSED(win); RGFW_UNUSED(channels) RGFW_UNUSED(a) RGFW_UNUSED(image) }
8767
8768const char RGFW_CURSORS[11][12] = {
8769 "default",
8770 "default",
8771 "text",
8772 "crosshair",
8773 "pointer",
8774 "ew-resize",
8775 "ns-resize",
8776 "nwse-resize",
8777 "nesw-resize",
8778 "move",
8779 "not-allowed"
8780};
8781
8782void RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) {
8783 RGFW_UNUSED(win)
8784 EM_ASM( { document.getElementById("canvas").style.cursor = UTF8ToString($0); }, RGFW_CURSORS[mouse]);
8785}
8786
8787void RGFW_window_setMouseDefault(RGFW_window* win) {
8788 RGFW_window_setMouseStandard(win, RGFW_MOUSE_NORMAL);
8789}
8790
8791void RGFW_window_showMouse(RGFW_window* win, i8 show) {
8792 if (show)
8793 RGFW_window_setMouseDefault(win);
8794 else
8795 EM_ASM(document.getElementById('canvas').style.cursor = 'none';);
8796}
8797
8798RGFW_point RGFW_getGlobalMousePoint(void) {
8799 RGFW_point point;
8800 point.x = EM_ASM_INT({
8801 return window.mouseX || 0;
8802 });
8803 point.y = EM_ASM_INT({
8804 return window.mouseY || 0;
8805 });
8806 return point;
8807}
8808
8809RGFW_point RGFW_window_getMousePoint(RGFW_window* win) {
8810 RGFW_UNUSED(win);
8811
8812 EmscriptenMouseEvent mouseEvent;
8813 emscripten_get_mouse_status(&mouseEvent);
8814 return RGFW_POINT( mouseEvent.targetX, mouseEvent.targetY);
8815}
8816
8817void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) {
8818 RGFW_UNUSED(win);
8819
8820 EM_ASM_({
8821 var canvas = document.getElementById('canvas');
8822 if ($0) {
8823 canvas.style.pointerEvents = 'none';
8824 } else {
8825 canvas.style.pointerEvents = 'auto';
8826 }
8827 }, passthrough);
8828}
8829
8830void RGFW_writeClipboard(const char* text, u32 textLen) {
8831 RGFW_UNUSED(textLen)
8832 EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, text);
8833}
8834
8835
8836char* RGFW_readClipboard(size_t* size) {
8837 /*
8838 placeholder code for later
8839 I'm not sure if this is possible do the the async stuff
8840 */
8841
8842 if (size != NULL)
8843 *size = 0;
8844
8845 char* str = (char*)malloc(1);
8846 str[0] = '\0';
8847
8848 return str;
8849}
8850
8851void RGFW_window_swapBuffers(RGFW_window* win) {
8852 RGFW_UNUSED(win);
8853
8854 #ifdef RGFW_BUFFER
8855 if (!(win->_winArgs & RGFW_NO_CPU_RENDER)) {
8856 glEnable(GL_TEXTURE_2D);
8857
8858 GLuint texture;
8859 glGenTextures(1,&texture);
8860
8861 glBindTexture(GL_TEXTURE_2D,texture);
8862
8863 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
8864 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
8865 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
8866 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
8867
8868 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, RGFW_bufferSize.w, RGFW_bufferSize.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, win->buffer);
8869
8870 float ratioX = ((float)win->r.w / (float)RGFW_bufferSize.w);
8871 float ratioY = ((float)win->r.h / (float)RGFW_bufferSize.h);
8872
8873 // Set up the viewport
8874 glClear(GL_COLOR_BUFFER_BIT);
8875
8876 glBegin(GL_TRIANGLES);
8877 glTexCoord2f(0, ratioY); glColor3f(1, 1, 1); glVertex2f(-1, -1);
8878 glTexCoord2f(0, 0); glColor3f(1, 1, 1); glVertex2f(-1, 1);
8879 glTexCoord2f(ratioX, ratioY); glColor3f(1, 1, 1); glVertex2f(1, -1);
8880
8881 glTexCoord2f(ratioX, 0); glColor3f(1, 1, 1); glVertex2f(1, 1);
8882 glTexCoord2f(ratioX, ratioY); glColor3f(1, 1, 1); glVertex2f(1, -1);
8883 glTexCoord2f(0, 0); glColor3f(1, 1, 1); glVertex2f(-1, 1);
8884 glEnd();
8885
8886 glDeleteTextures(1, &texture);
8887 }
8888 #endif
8889
8890#ifndef RGFW_WEBGPU
8891 emscripten_webgl_commit_frame();
8892#endif
8893 emscripten_sleep(0);
8894}
8895
8896
8897void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) {
8898#ifndef RGFW_WEBGPU
8899 if (win == NULL)
8900 emscripten_webgl_make_context_current(0);
8901 else
8902 emscripten_webgl_make_context_current(win->src.ctx);
8903#endif
8904}
8905
8906#ifndef RGFW_EGL
8907void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { RGFW_UNUSED(win); RGFW_UNUSED(swapInterval); }
8908#endif
8909
8910void RGFW_window_close(RGFW_window* win) {
8911#ifndef RGFW_WEBGPU
8912 emscripten_webgl_destroy_context(win->src.ctx);
8913#endif
8914
8915 free(win);
8916}
8917
8918int RGFW_innerWidth(void) { return EM_ASM_INT({ return window.innerWidth; }); }
8919int RGFW_innerHeight(void) { return EM_ASM_INT({ return window.innerHeight; }); }
8920
8921RGFW_area RGFW_getScreenSize(void) {
8922 return RGFW_AREA(RGFW_innerWidth(), RGFW_innerHeight());
8923}
8924
8925void* RGFW_getProcAddress(const char* procname) {
8926 return emscripten_webgl_get_proc_address(procname);
8927}
8928
8929void RGFW_sleep(u64 milisecond) {
8930 emscripten_sleep(milisecond);
8931}
8932
8933u64 RGFW_getTimeNS(void) {
8934 return emscripten_get_now() * 1e+6;
8935}
8936
8937u64 RGFW_getTime(void) {
8938 return emscripten_get_now() * 1000;
8939}
8940
8941void RGFW_releaseCursor(RGFW_window* win) {
8942 RGFW_UNUSED(win);
8943 emscripten_exit_pointerlock();
8944}
8945
8946void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) {
8947 RGFW_UNUSED(win); RGFW_UNUSED(r);
8948
8949 emscripten_request_pointerlock("#canvas", 1);
8950}
8951
8952
8953void RGFW_window_setName(RGFW_window* win, char* name) {
8954 RGFW_UNUSED(win);
8955 emscripten_set_window_title(name);
8956}
8957
8958/* unsupported functions */
8959RGFW_monitor* RGFW_getMonitors(void) { return NULL; }
8960RGFW_monitor RGFW_getPrimaryMonitor(void) { return (RGFW_monitor){}; }
8961void RGFW_window_move(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win) RGFW_UNUSED(v) }
8962void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win) RGFW_UNUSED(a) }
8963void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win) RGFW_UNUSED(a) }
8964void RGFW_window_minimize(RGFW_window* win) { RGFW_UNUSED(win)}
8965void RGFW_window_restore(RGFW_window* win) { RGFW_UNUSED(win) }
8966void RGFW_window_setBorder(RGFW_window* win, b8 border) { RGFW_UNUSED(win) RGFW_UNUSED(border) }
8967void RGFW_window_setIcon(RGFW_window* win, u8* icon, RGFW_area a, i32 channels) { RGFW_UNUSED(win) RGFW_UNUSED(icon) RGFW_UNUSED(a) RGFW_UNUSED(channels) }
8968void RGFW_window_hide(RGFW_window* win) { RGFW_UNUSED(win) }
8969void RGFW_window_show(RGFW_window* win) {RGFW_UNUSED(win) }
8970b8 RGFW_window_isHidden(RGFW_window* win) { RGFW_UNUSED(win) return 0; }
8971b8 RGFW_window_isMinimized(RGFW_window* win) { RGFW_UNUSED(win) return 0; }
8972b8 RGFW_window_isMaximized(RGFW_window* win) { RGFW_UNUSED(win) return 0; }
8973RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { RGFW_UNUSED(win) return (RGFW_monitor){}; }
8974
8975#endif
8976
8977/* end of web asm defines */
8978
8979/* unix (macOS, linux, web asm) only stuff */
8980#if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WEBASM) || defined(RGFW_WAYLAND)
8981/* unix threading */
8982#ifndef RGFW_NO_THREADS
8983#include <pthread.h>
8984
8985 RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args) {
8986 RGFW_UNUSED(args);
8987
8988 RGFW_thread t;
8989 pthread_create((pthread_t*) &t, NULL, *ptr, NULL);
8990 return t;
8991 }
8992 void RGFW_cancelThread(RGFW_thread thread) { pthread_cancel((pthread_t) thread); }
8993 void RGFW_joinThread(RGFW_thread thread) { pthread_join((pthread_t) thread, NULL); }
8994#ifdef __linux__
8995 void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { pthread_setschedprio((pthread_t)thread, priority); }
8996#endif
8997#endif
8998
8999#ifndef RGFW_WEBASM
9000/* unix sleep */
9001 void RGFW_sleep(u64 ms) {
9002 struct timespec time;
9003 time.tv_sec = 0;
9004 time.tv_nsec = ms * 1e+6;
9005
9006 nanosleep(&time, NULL);
9007 }
9008#endif
9009
9010#endif /* end of unix / mac stuff*/
9011#endif /*RGFW_IMPLEMENTATION*/
9012
9013#if defined(__cplusplus) && !defined(__EMSCRIPTEN__)
9014}
9015#endif
diff --git a/raylib/src/external/cgltf.h b/raylib/src/external/cgltf.h
new file mode 100644
index 0000000..36fd644
--- /dev/null
+++ b/raylib/src/external/cgltf.h
@@ -0,0 +1,7081 @@
1/**
2 * cgltf - a single-file glTF 2.0 parser written in C99.
3 *
4 * Version: 1.14
5 *
6 * Website: https://github.com/jkuhlmann/cgltf
7 *
8 * Distributed under the MIT License, see notice at the end of this file.
9 *
10 * Building:
11 * Include this file where you need the struct and function
12 * declarations. Have exactly one source file where you define
13 * `CGLTF_IMPLEMENTATION` before including this file to get the
14 * function definitions.
15 *
16 * Reference:
17 * `cgltf_result cgltf_parse(const cgltf_options*, const void*,
18 * cgltf_size, cgltf_data**)` parses both glTF and GLB data. If
19 * this function returns `cgltf_result_success`, you have to call
20 * `cgltf_free()` on the created `cgltf_data*` variable.
21 * Note that contents of external files for buffers and images are not
22 * automatically loaded. You'll need to read these files yourself using
23 * URIs in the `cgltf_data` structure.
24 *
25 * `cgltf_options` is the struct passed to `cgltf_parse()` to control
26 * parts of the parsing process. You can use it to force the file type
27 * and provide memory allocation as well as file operation callbacks.
28 * Should be zero-initialized to trigger default behavior.
29 *
30 * `cgltf_data` is the struct allocated and filled by `cgltf_parse()`.
31 * It generally mirrors the glTF format as described by the spec (see
32 * https://github.com/KhronosGroup/glTF/tree/master/specification/2.0).
33 *
34 * `void cgltf_free(cgltf_data*)` frees the allocated `cgltf_data`
35 * variable.
36 *
37 * `cgltf_result cgltf_load_buffers(const cgltf_options*, cgltf_data*,
38 * const char* gltf_path)` can be optionally called to open and read buffer
39 * files using the `FILE*` APIs. The `gltf_path` argument is the path to
40 * the original glTF file, which allows the parser to resolve the path to
41 * buffer files.
42 *
43 * `cgltf_result cgltf_load_buffer_base64(const cgltf_options* options,
44 * cgltf_size size, const char* base64, void** out_data)` decodes
45 * base64-encoded data content. Used internally by `cgltf_load_buffers()`.
46 * This is useful when decoding data URIs in images.
47 *
48 * `cgltf_result cgltf_parse_file(const cgltf_options* options, const
49 * char* path, cgltf_data** out_data)` can be used to open the given
50 * file using `FILE*` APIs and parse the data using `cgltf_parse()`.
51 *
52 * `cgltf_result cgltf_validate(cgltf_data*)` can be used to do additional
53 * checks to make sure the parsed glTF data is valid.
54 *
55 * `cgltf_node_transform_local` converts the translation / rotation / scale properties of a node
56 * into a mat4.
57 *
58 * `cgltf_node_transform_world` calls `cgltf_node_transform_local` on every ancestor in order
59 * to compute the root-to-node transformation.
60 *
61 * `cgltf_accessor_unpack_floats` reads in the data from an accessor, applies sparse data (if any),
62 * and converts them to floating point. Assumes that `cgltf_load_buffers` has already been called.
63 * By passing null for the output pointer, users can find out how many floats are required in the
64 * output buffer.
65 *
66 * `cgltf_accessor_unpack_indices` reads in the index data from an accessor. Assumes that
67 * `cgltf_load_buffers` has already been called. By passing null for the output pointer, users can
68 * find out how many indices are required in the output buffer. Returns 0 if the accessor is
69 * sparse or if the output component size is less than the accessor's component size.
70 *
71 * `cgltf_num_components` is a tiny utility that tells you the dimensionality of
72 * a certain accessor type. This can be used before `cgltf_accessor_unpack_floats` to help allocate
73 * the necessary amount of memory. `cgltf_component_size` and `cgltf_calc_size` exist for
74 * similar purposes.
75 *
76 * `cgltf_accessor_read_float` reads a certain element from a non-sparse accessor and converts it to
77 * floating point, assuming that `cgltf_load_buffers` has already been called. The passed-in element
78 * size is the number of floats in the output buffer, which should be in the range [1, 16]. Returns
79 * false if the passed-in element_size is too small, or if the accessor is sparse.
80 *
81 * `cgltf_accessor_read_uint` is similar to its floating-point counterpart, but limited to reading
82 * vector types and does not support matrix types. The passed-in element size is the number of uints
83 * in the output buffer, which should be in the range [1, 4]. Returns false if the passed-in
84 * element_size is too small, or if the accessor is sparse.
85 *
86 * `cgltf_accessor_read_index` is similar to its floating-point counterpart, but it returns size_t
87 * and only works with single-component data types.
88 *
89 * `cgltf_copy_extras_json` allows users to retrieve the "extras" data that can be attached to many
90 * glTF objects (which can be arbitrary JSON data). This is a legacy function, consider using
91 * cgltf_extras::data directly instead. You can parse this data using your own JSON parser
92 * or, if you've included the cgltf implementation using the integrated JSMN JSON parser.
93 */
94#ifndef CGLTF_H_INCLUDED__
95#define CGLTF_H_INCLUDED__
96
97#include <stddef.h>
98#include <stdint.h> /* For uint8_t, uint32_t */
99
100#ifdef __cplusplus
101extern "C" {
102#endif
103
104typedef size_t cgltf_size;
105typedef long long int cgltf_ssize;
106typedef float cgltf_float;
107typedef int cgltf_int;
108typedef unsigned int cgltf_uint;
109typedef int cgltf_bool;
110
111typedef enum cgltf_file_type
112{
113 cgltf_file_type_invalid,
114 cgltf_file_type_gltf,
115 cgltf_file_type_glb,
116 cgltf_file_type_max_enum
117} cgltf_file_type;
118
119typedef enum cgltf_result
120{
121 cgltf_result_success,
122 cgltf_result_data_too_short,
123 cgltf_result_unknown_format,
124 cgltf_result_invalid_json,
125 cgltf_result_invalid_gltf,
126 cgltf_result_invalid_options,
127 cgltf_result_file_not_found,
128 cgltf_result_io_error,
129 cgltf_result_out_of_memory,
130 cgltf_result_legacy_gltf,
131 cgltf_result_max_enum
132} cgltf_result;
133
134typedef struct cgltf_memory_options
135{
136 void* (*alloc_func)(void* user, cgltf_size size);
137 void (*free_func) (void* user, void* ptr);
138 void* user_data;
139} cgltf_memory_options;
140
141typedef struct cgltf_file_options
142{
143 cgltf_result(*read)(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, const char* path, cgltf_size* size, void** data);
144 void (*release)(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, void* data);
145 void* user_data;
146} cgltf_file_options;
147
148typedef struct cgltf_options
149{
150 cgltf_file_type type; /* invalid == auto detect */
151 cgltf_size json_token_count; /* 0 == auto */
152 cgltf_memory_options memory;
153 cgltf_file_options file;
154} cgltf_options;
155
156typedef enum cgltf_buffer_view_type
157{
158 cgltf_buffer_view_type_invalid,
159 cgltf_buffer_view_type_indices,
160 cgltf_buffer_view_type_vertices,
161 cgltf_buffer_view_type_max_enum
162} cgltf_buffer_view_type;
163
164typedef enum cgltf_attribute_type
165{
166 cgltf_attribute_type_invalid,
167 cgltf_attribute_type_position,
168 cgltf_attribute_type_normal,
169 cgltf_attribute_type_tangent,
170 cgltf_attribute_type_texcoord,
171 cgltf_attribute_type_color,
172 cgltf_attribute_type_joints,
173 cgltf_attribute_type_weights,
174 cgltf_attribute_type_custom,
175 cgltf_attribute_type_max_enum
176} cgltf_attribute_type;
177
178typedef enum cgltf_component_type
179{
180 cgltf_component_type_invalid,
181 cgltf_component_type_r_8, /* BYTE */
182 cgltf_component_type_r_8u, /* UNSIGNED_BYTE */
183 cgltf_component_type_r_16, /* SHORT */
184 cgltf_component_type_r_16u, /* UNSIGNED_SHORT */
185 cgltf_component_type_r_32u, /* UNSIGNED_INT */
186 cgltf_component_type_r_32f, /* FLOAT */
187 cgltf_component_type_max_enum
188} cgltf_component_type;
189
190typedef enum cgltf_type
191{
192 cgltf_type_invalid,
193 cgltf_type_scalar,
194 cgltf_type_vec2,
195 cgltf_type_vec3,
196 cgltf_type_vec4,
197 cgltf_type_mat2,
198 cgltf_type_mat3,
199 cgltf_type_mat4,
200 cgltf_type_max_enum
201} cgltf_type;
202
203typedef enum cgltf_primitive_type
204{
205 cgltf_primitive_type_invalid,
206 cgltf_primitive_type_points,
207 cgltf_primitive_type_lines,
208 cgltf_primitive_type_line_loop,
209 cgltf_primitive_type_line_strip,
210 cgltf_primitive_type_triangles,
211 cgltf_primitive_type_triangle_strip,
212 cgltf_primitive_type_triangle_fan,
213 cgltf_primitive_type_max_enum
214} cgltf_primitive_type;
215
216typedef enum cgltf_alpha_mode
217{
218 cgltf_alpha_mode_opaque,
219 cgltf_alpha_mode_mask,
220 cgltf_alpha_mode_blend,
221 cgltf_alpha_mode_max_enum
222} cgltf_alpha_mode;
223
224typedef enum cgltf_animation_path_type {
225 cgltf_animation_path_type_invalid,
226 cgltf_animation_path_type_translation,
227 cgltf_animation_path_type_rotation,
228 cgltf_animation_path_type_scale,
229 cgltf_animation_path_type_weights,
230 cgltf_animation_path_type_max_enum
231} cgltf_animation_path_type;
232
233typedef enum cgltf_interpolation_type {
234 cgltf_interpolation_type_linear,
235 cgltf_interpolation_type_step,
236 cgltf_interpolation_type_cubic_spline,
237 cgltf_interpolation_type_max_enum
238} cgltf_interpolation_type;
239
240typedef enum cgltf_camera_type {
241 cgltf_camera_type_invalid,
242 cgltf_camera_type_perspective,
243 cgltf_camera_type_orthographic,
244 cgltf_camera_type_max_enum
245} cgltf_camera_type;
246
247typedef enum cgltf_light_type {
248 cgltf_light_type_invalid,
249 cgltf_light_type_directional,
250 cgltf_light_type_point,
251 cgltf_light_type_spot,
252 cgltf_light_type_max_enum
253} cgltf_light_type;
254
255typedef enum cgltf_data_free_method {
256 cgltf_data_free_method_none,
257 cgltf_data_free_method_file_release,
258 cgltf_data_free_method_memory_free,
259 cgltf_data_free_method_max_enum
260} cgltf_data_free_method;
261
262typedef struct cgltf_extras {
263 cgltf_size start_offset; /* this field is deprecated and will be removed in the future; use data instead */
264 cgltf_size end_offset; /* this field is deprecated and will be removed in the future; use data instead */
265
266 char* data;
267} cgltf_extras;
268
269typedef struct cgltf_extension {
270 char* name;
271 char* data;
272} cgltf_extension;
273
274typedef struct cgltf_buffer
275{
276 char* name;
277 cgltf_size size;
278 char* uri;
279 void* data; /* loaded by cgltf_load_buffers */
280 cgltf_data_free_method data_free_method;
281 cgltf_extras extras;
282 cgltf_size extensions_count;
283 cgltf_extension* extensions;
284} cgltf_buffer;
285
286typedef enum cgltf_meshopt_compression_mode {
287 cgltf_meshopt_compression_mode_invalid,
288 cgltf_meshopt_compression_mode_attributes,
289 cgltf_meshopt_compression_mode_triangles,
290 cgltf_meshopt_compression_mode_indices,
291 cgltf_meshopt_compression_mode_max_enum
292} cgltf_meshopt_compression_mode;
293
294typedef enum cgltf_meshopt_compression_filter {
295 cgltf_meshopt_compression_filter_none,
296 cgltf_meshopt_compression_filter_octahedral,
297 cgltf_meshopt_compression_filter_quaternion,
298 cgltf_meshopt_compression_filter_exponential,
299 cgltf_meshopt_compression_filter_max_enum
300} cgltf_meshopt_compression_filter;
301
302typedef struct cgltf_meshopt_compression
303{
304 cgltf_buffer* buffer;
305 cgltf_size offset;
306 cgltf_size size;
307 cgltf_size stride;
308 cgltf_size count;
309 cgltf_meshopt_compression_mode mode;
310 cgltf_meshopt_compression_filter filter;
311} cgltf_meshopt_compression;
312
313typedef struct cgltf_buffer_view
314{
315 char *name;
316 cgltf_buffer* buffer;
317 cgltf_size offset;
318 cgltf_size size;
319 cgltf_size stride; /* 0 == automatically determined by accessor */
320 cgltf_buffer_view_type type;
321 void* data; /* overrides buffer->data if present, filled by extensions */
322 cgltf_bool has_meshopt_compression;
323 cgltf_meshopt_compression meshopt_compression;
324 cgltf_extras extras;
325 cgltf_size extensions_count;
326 cgltf_extension* extensions;
327} cgltf_buffer_view;
328
329typedef struct cgltf_accessor_sparse
330{
331 cgltf_size count;
332 cgltf_buffer_view* indices_buffer_view;
333 cgltf_size indices_byte_offset;
334 cgltf_component_type indices_component_type;
335 cgltf_buffer_view* values_buffer_view;
336 cgltf_size values_byte_offset;
337} cgltf_accessor_sparse;
338
339typedef struct cgltf_accessor
340{
341 char* name;
342 cgltf_component_type component_type;
343 cgltf_bool normalized;
344 cgltf_type type;
345 cgltf_size offset;
346 cgltf_size count;
347 cgltf_size stride;
348 cgltf_buffer_view* buffer_view;
349 cgltf_bool has_min;
350 cgltf_float min[16];
351 cgltf_bool has_max;
352 cgltf_float max[16];
353 cgltf_bool is_sparse;
354 cgltf_accessor_sparse sparse;
355 cgltf_extras extras;
356 cgltf_size extensions_count;
357 cgltf_extension* extensions;
358} cgltf_accessor;
359
360typedef struct cgltf_attribute
361{
362 char* name;
363 cgltf_attribute_type type;
364 cgltf_int index;
365 cgltf_accessor* data;
366} cgltf_attribute;
367
368typedef struct cgltf_image
369{
370 char* name;
371 char* uri;
372 cgltf_buffer_view* buffer_view;
373 char* mime_type;
374 cgltf_extras extras;
375 cgltf_size extensions_count;
376 cgltf_extension* extensions;
377} cgltf_image;
378
379typedef struct cgltf_sampler
380{
381 char* name;
382 cgltf_int mag_filter;
383 cgltf_int min_filter;
384 cgltf_int wrap_s;
385 cgltf_int wrap_t;
386 cgltf_extras extras;
387 cgltf_size extensions_count;
388 cgltf_extension* extensions;
389} cgltf_sampler;
390
391typedef struct cgltf_texture
392{
393 char* name;
394 cgltf_image* image;
395 cgltf_sampler* sampler;
396 cgltf_bool has_basisu;
397 cgltf_image* basisu_image;
398 cgltf_bool has_webp;
399 cgltf_image* webp_image;
400 cgltf_extras extras;
401 cgltf_size extensions_count;
402 cgltf_extension* extensions;
403} cgltf_texture;
404
405typedef struct cgltf_texture_transform
406{
407 cgltf_float offset[2];
408 cgltf_float rotation;
409 cgltf_float scale[2];
410 cgltf_bool has_texcoord;
411 cgltf_int texcoord;
412} cgltf_texture_transform;
413
414typedef struct cgltf_texture_view
415{
416 cgltf_texture* texture;
417 cgltf_int texcoord;
418 cgltf_float scale; /* equivalent to strength for occlusion_texture */
419 cgltf_bool has_transform;
420 cgltf_texture_transform transform;
421} cgltf_texture_view;
422
423typedef struct cgltf_pbr_metallic_roughness
424{
425 cgltf_texture_view base_color_texture;
426 cgltf_texture_view metallic_roughness_texture;
427
428 cgltf_float base_color_factor[4];
429 cgltf_float metallic_factor;
430 cgltf_float roughness_factor;
431} cgltf_pbr_metallic_roughness;
432
433typedef struct cgltf_pbr_specular_glossiness
434{
435 cgltf_texture_view diffuse_texture;
436 cgltf_texture_view specular_glossiness_texture;
437
438 cgltf_float diffuse_factor[4];
439 cgltf_float specular_factor[3];
440 cgltf_float glossiness_factor;
441} cgltf_pbr_specular_glossiness;
442
443typedef struct cgltf_clearcoat
444{
445 cgltf_texture_view clearcoat_texture;
446 cgltf_texture_view clearcoat_roughness_texture;
447 cgltf_texture_view clearcoat_normal_texture;
448
449 cgltf_float clearcoat_factor;
450 cgltf_float clearcoat_roughness_factor;
451} cgltf_clearcoat;
452
453typedef struct cgltf_transmission
454{
455 cgltf_texture_view transmission_texture;
456 cgltf_float transmission_factor;
457} cgltf_transmission;
458
459typedef struct cgltf_ior
460{
461 cgltf_float ior;
462} cgltf_ior;
463
464typedef struct cgltf_specular
465{
466 cgltf_texture_view specular_texture;
467 cgltf_texture_view specular_color_texture;
468 cgltf_float specular_color_factor[3];
469 cgltf_float specular_factor;
470} cgltf_specular;
471
472typedef struct cgltf_volume
473{
474 cgltf_texture_view thickness_texture;
475 cgltf_float thickness_factor;
476 cgltf_float attenuation_color[3];
477 cgltf_float attenuation_distance;
478} cgltf_volume;
479
480typedef struct cgltf_sheen
481{
482 cgltf_texture_view sheen_color_texture;
483 cgltf_float sheen_color_factor[3];
484 cgltf_texture_view sheen_roughness_texture;
485 cgltf_float sheen_roughness_factor;
486} cgltf_sheen;
487
488typedef struct cgltf_emissive_strength
489{
490 cgltf_float emissive_strength;
491} cgltf_emissive_strength;
492
493typedef struct cgltf_iridescence
494{
495 cgltf_float iridescence_factor;
496 cgltf_texture_view iridescence_texture;
497 cgltf_float iridescence_ior;
498 cgltf_float iridescence_thickness_min;
499 cgltf_float iridescence_thickness_max;
500 cgltf_texture_view iridescence_thickness_texture;
501} cgltf_iridescence;
502
503typedef struct cgltf_anisotropy
504{
505 cgltf_float anisotropy_strength;
506 cgltf_float anisotropy_rotation;
507 cgltf_texture_view anisotropy_texture;
508} cgltf_anisotropy;
509
510typedef struct cgltf_dispersion
511{
512 cgltf_float dispersion;
513} cgltf_dispersion;
514
515typedef struct cgltf_material
516{
517 char* name;
518 cgltf_bool has_pbr_metallic_roughness;
519 cgltf_bool has_pbr_specular_glossiness;
520 cgltf_bool has_clearcoat;
521 cgltf_bool has_transmission;
522 cgltf_bool has_volume;
523 cgltf_bool has_ior;
524 cgltf_bool has_specular;
525 cgltf_bool has_sheen;
526 cgltf_bool has_emissive_strength;
527 cgltf_bool has_iridescence;
528 cgltf_bool has_anisotropy;
529 cgltf_bool has_dispersion;
530 cgltf_pbr_metallic_roughness pbr_metallic_roughness;
531 cgltf_pbr_specular_glossiness pbr_specular_glossiness;
532 cgltf_clearcoat clearcoat;
533 cgltf_ior ior;
534 cgltf_specular specular;
535 cgltf_sheen sheen;
536 cgltf_transmission transmission;
537 cgltf_volume volume;
538 cgltf_emissive_strength emissive_strength;
539 cgltf_iridescence iridescence;
540 cgltf_anisotropy anisotropy;
541 cgltf_dispersion dispersion;
542 cgltf_texture_view normal_texture;
543 cgltf_texture_view occlusion_texture;
544 cgltf_texture_view emissive_texture;
545 cgltf_float emissive_factor[3];
546 cgltf_alpha_mode alpha_mode;
547 cgltf_float alpha_cutoff;
548 cgltf_bool double_sided;
549 cgltf_bool unlit;
550 cgltf_extras extras;
551 cgltf_size extensions_count;
552 cgltf_extension* extensions;
553} cgltf_material;
554
555typedef struct cgltf_material_mapping
556{
557 cgltf_size variant;
558 cgltf_material* material;
559 cgltf_extras extras;
560} cgltf_material_mapping;
561
562typedef struct cgltf_morph_target {
563 cgltf_attribute* attributes;
564 cgltf_size attributes_count;
565} cgltf_morph_target;
566
567typedef struct cgltf_draco_mesh_compression {
568 cgltf_buffer_view* buffer_view;
569 cgltf_attribute* attributes;
570 cgltf_size attributes_count;
571} cgltf_draco_mesh_compression;
572
573typedef struct cgltf_mesh_gpu_instancing {
574 cgltf_attribute* attributes;
575 cgltf_size attributes_count;
576} cgltf_mesh_gpu_instancing;
577
578typedef struct cgltf_primitive {
579 cgltf_primitive_type type;
580 cgltf_accessor* indices;
581 cgltf_material* material;
582 cgltf_attribute* attributes;
583 cgltf_size attributes_count;
584 cgltf_morph_target* targets;
585 cgltf_size targets_count;
586 cgltf_extras extras;
587 cgltf_bool has_draco_mesh_compression;
588 cgltf_draco_mesh_compression draco_mesh_compression;
589 cgltf_material_mapping* mappings;
590 cgltf_size mappings_count;
591 cgltf_size extensions_count;
592 cgltf_extension* extensions;
593} cgltf_primitive;
594
595typedef struct cgltf_mesh {
596 char* name;
597 cgltf_primitive* primitives;
598 cgltf_size primitives_count;
599 cgltf_float* weights;
600 cgltf_size weights_count;
601 char** target_names;
602 cgltf_size target_names_count;
603 cgltf_extras extras;
604 cgltf_size extensions_count;
605 cgltf_extension* extensions;
606} cgltf_mesh;
607
608typedef struct cgltf_node cgltf_node;
609
610typedef struct cgltf_skin {
611 char* name;
612 cgltf_node** joints;
613 cgltf_size joints_count;
614 cgltf_node* skeleton;
615 cgltf_accessor* inverse_bind_matrices;
616 cgltf_extras extras;
617 cgltf_size extensions_count;
618 cgltf_extension* extensions;
619} cgltf_skin;
620
621typedef struct cgltf_camera_perspective {
622 cgltf_bool has_aspect_ratio;
623 cgltf_float aspect_ratio;
624 cgltf_float yfov;
625 cgltf_bool has_zfar;
626 cgltf_float zfar;
627 cgltf_float znear;
628 cgltf_extras extras;
629} cgltf_camera_perspective;
630
631typedef struct cgltf_camera_orthographic {
632 cgltf_float xmag;
633 cgltf_float ymag;
634 cgltf_float zfar;
635 cgltf_float znear;
636 cgltf_extras extras;
637} cgltf_camera_orthographic;
638
639typedef struct cgltf_camera {
640 char* name;
641 cgltf_camera_type type;
642 union {
643 cgltf_camera_perspective perspective;
644 cgltf_camera_orthographic orthographic;
645 } data;
646 cgltf_extras extras;
647 cgltf_size extensions_count;
648 cgltf_extension* extensions;
649} cgltf_camera;
650
651typedef struct cgltf_light {
652 char* name;
653 cgltf_float color[3];
654 cgltf_float intensity;
655 cgltf_light_type type;
656 cgltf_float range;
657 cgltf_float spot_inner_cone_angle;
658 cgltf_float spot_outer_cone_angle;
659 cgltf_extras extras;
660} cgltf_light;
661
662struct cgltf_node {
663 char* name;
664 cgltf_node* parent;
665 cgltf_node** children;
666 cgltf_size children_count;
667 cgltf_skin* skin;
668 cgltf_mesh* mesh;
669 cgltf_camera* camera;
670 cgltf_light* light;
671 cgltf_float* weights;
672 cgltf_size weights_count;
673 cgltf_bool has_translation;
674 cgltf_bool has_rotation;
675 cgltf_bool has_scale;
676 cgltf_bool has_matrix;
677 cgltf_float translation[3];
678 cgltf_float rotation[4];
679 cgltf_float scale[3];
680 cgltf_float matrix[16];
681 cgltf_extras extras;
682 cgltf_bool has_mesh_gpu_instancing;
683 cgltf_mesh_gpu_instancing mesh_gpu_instancing;
684 cgltf_size extensions_count;
685 cgltf_extension* extensions;
686};
687
688typedef struct cgltf_scene {
689 char* name;
690 cgltf_node** nodes;
691 cgltf_size nodes_count;
692 cgltf_extras extras;
693 cgltf_size extensions_count;
694 cgltf_extension* extensions;
695} cgltf_scene;
696
697typedef struct cgltf_animation_sampler {
698 cgltf_accessor* input;
699 cgltf_accessor* output;
700 cgltf_interpolation_type interpolation;
701 cgltf_extras extras;
702 cgltf_size extensions_count;
703 cgltf_extension* extensions;
704} cgltf_animation_sampler;
705
706typedef struct cgltf_animation_channel {
707 cgltf_animation_sampler* sampler;
708 cgltf_node* target_node;
709 cgltf_animation_path_type target_path;
710 cgltf_extras extras;
711 cgltf_size extensions_count;
712 cgltf_extension* extensions;
713} cgltf_animation_channel;
714
715typedef struct cgltf_animation {
716 char* name;
717 cgltf_animation_sampler* samplers;
718 cgltf_size samplers_count;
719 cgltf_animation_channel* channels;
720 cgltf_size channels_count;
721 cgltf_extras extras;
722 cgltf_size extensions_count;
723 cgltf_extension* extensions;
724} cgltf_animation;
725
726typedef struct cgltf_material_variant
727{
728 char* name;
729 cgltf_extras extras;
730} cgltf_material_variant;
731
732typedef struct cgltf_asset {
733 char* copyright;
734 char* generator;
735 char* version;
736 char* min_version;
737 cgltf_extras extras;
738 cgltf_size extensions_count;
739 cgltf_extension* extensions;
740} cgltf_asset;
741
742typedef struct cgltf_data
743{
744 cgltf_file_type file_type;
745 void* file_data;
746
747 cgltf_asset asset;
748
749 cgltf_mesh* meshes;
750 cgltf_size meshes_count;
751
752 cgltf_material* materials;
753 cgltf_size materials_count;
754
755 cgltf_accessor* accessors;
756 cgltf_size accessors_count;
757
758 cgltf_buffer_view* buffer_views;
759 cgltf_size buffer_views_count;
760
761 cgltf_buffer* buffers;
762 cgltf_size buffers_count;
763
764 cgltf_image* images;
765 cgltf_size images_count;
766
767 cgltf_texture* textures;
768 cgltf_size textures_count;
769
770 cgltf_sampler* samplers;
771 cgltf_size samplers_count;
772
773 cgltf_skin* skins;
774 cgltf_size skins_count;
775
776 cgltf_camera* cameras;
777 cgltf_size cameras_count;
778
779 cgltf_light* lights;
780 cgltf_size lights_count;
781
782 cgltf_node* nodes;
783 cgltf_size nodes_count;
784
785 cgltf_scene* scenes;
786 cgltf_size scenes_count;
787
788 cgltf_scene* scene;
789
790 cgltf_animation* animations;
791 cgltf_size animations_count;
792
793 cgltf_material_variant* variants;
794 cgltf_size variants_count;
795
796 cgltf_extras extras;
797
798 cgltf_size data_extensions_count;
799 cgltf_extension* data_extensions;
800
801 char** extensions_used;
802 cgltf_size extensions_used_count;
803
804 char** extensions_required;
805 cgltf_size extensions_required_count;
806
807 const char* json;
808 cgltf_size json_size;
809
810 const void* bin;
811 cgltf_size bin_size;
812
813 cgltf_memory_options memory;
814 cgltf_file_options file;
815} cgltf_data;
816
817cgltf_result cgltf_parse(
818 const cgltf_options* options,
819 const void* data,
820 cgltf_size size,
821 cgltf_data** out_data);
822
823cgltf_result cgltf_parse_file(
824 const cgltf_options* options,
825 const char* path,
826 cgltf_data** out_data);
827
828cgltf_result cgltf_load_buffers(
829 const cgltf_options* options,
830 cgltf_data* data,
831 const char* gltf_path);
832
833cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, cgltf_size size, const char* base64, void** out_data);
834
835cgltf_size cgltf_decode_string(char* string);
836cgltf_size cgltf_decode_uri(char* uri);
837
838cgltf_result cgltf_validate(cgltf_data* data);
839
840void cgltf_free(cgltf_data* data);
841
842void cgltf_node_transform_local(const cgltf_node* node, cgltf_float* out_matrix);
843void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix);
844
845const uint8_t* cgltf_buffer_view_data(const cgltf_buffer_view* view);
846
847cgltf_bool cgltf_accessor_read_float(const cgltf_accessor* accessor, cgltf_size index, cgltf_float* out, cgltf_size element_size);
848cgltf_bool cgltf_accessor_read_uint(const cgltf_accessor* accessor, cgltf_size index, cgltf_uint* out, cgltf_size element_size);
849cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size index);
850
851cgltf_size cgltf_num_components(cgltf_type type);
852cgltf_size cgltf_component_size(cgltf_component_type component_type);
853cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type);
854
855cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_float* out, cgltf_size float_count);
856cgltf_size cgltf_accessor_unpack_indices(const cgltf_accessor* accessor, void* out, cgltf_size out_component_size, cgltf_size index_count);
857
858/* this function is deprecated and will be removed in the future; use cgltf_extras::data instead */
859cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* extras, char* dest, cgltf_size* dest_size);
860
861cgltf_size cgltf_mesh_index(const cgltf_data* data, const cgltf_mesh* object);
862cgltf_size cgltf_material_index(const cgltf_data* data, const cgltf_material* object);
863cgltf_size cgltf_accessor_index(const cgltf_data* data, const cgltf_accessor* object);
864cgltf_size cgltf_buffer_view_index(const cgltf_data* data, const cgltf_buffer_view* object);
865cgltf_size cgltf_buffer_index(const cgltf_data* data, const cgltf_buffer* object);
866cgltf_size cgltf_image_index(const cgltf_data* data, const cgltf_image* object);
867cgltf_size cgltf_texture_index(const cgltf_data* data, const cgltf_texture* object);
868cgltf_size cgltf_sampler_index(const cgltf_data* data, const cgltf_sampler* object);
869cgltf_size cgltf_skin_index(const cgltf_data* data, const cgltf_skin* object);
870cgltf_size cgltf_camera_index(const cgltf_data* data, const cgltf_camera* object);
871cgltf_size cgltf_light_index(const cgltf_data* data, const cgltf_light* object);
872cgltf_size cgltf_node_index(const cgltf_data* data, const cgltf_node* object);
873cgltf_size cgltf_scene_index(const cgltf_data* data, const cgltf_scene* object);
874cgltf_size cgltf_animation_index(const cgltf_data* data, const cgltf_animation* object);
875cgltf_size cgltf_animation_sampler_index(const cgltf_animation* animation, const cgltf_animation_sampler* object);
876cgltf_size cgltf_animation_channel_index(const cgltf_animation* animation, const cgltf_animation_channel* object);
877
878#ifdef __cplusplus
879}
880#endif
881
882#endif /* #ifndef CGLTF_H_INCLUDED__ */
883
884/*
885 *
886 * Stop now, if you are only interested in the API.
887 * Below, you find the implementation.
888 *
889 */
890
891#if defined(__INTELLISENSE__) || defined(__JETBRAINS_IDE__)
892/* This makes MSVC/CLion intellisense work. */
893#define CGLTF_IMPLEMENTATION
894#endif
895
896#ifdef CGLTF_IMPLEMENTATION
897
898#include <assert.h> /* For assert */
899#include <string.h> /* For strncpy */
900#include <stdio.h> /* For fopen */
901#include <limits.h> /* For UINT_MAX etc */
902#include <float.h> /* For FLT_MAX */
903
904#if !defined(CGLTF_MALLOC) || !defined(CGLTF_FREE) || !defined(CGLTF_ATOI) || !defined(CGLTF_ATOF) || !defined(CGLTF_ATOLL)
905#include <stdlib.h> /* For malloc, free, atoi, atof */
906#endif
907
908/* JSMN_PARENT_LINKS is necessary to make parsing large structures linear in input size */
909#define JSMN_PARENT_LINKS
910
911/* JSMN_STRICT is necessary to reject invalid JSON documents */
912#define JSMN_STRICT
913
914/*
915 * -- jsmn.h start --
916 * Source: https://github.com/zserge/jsmn
917 * License: MIT
918 */
919typedef enum {
920 JSMN_UNDEFINED = 0,
921 JSMN_OBJECT = 1,
922 JSMN_ARRAY = 2,
923 JSMN_STRING = 3,
924 JSMN_PRIMITIVE = 4
925} jsmntype_t;
926enum jsmnerr {
927 /* Not enough tokens were provided */
928 JSMN_ERROR_NOMEM = -1,
929 /* Invalid character inside JSON string */
930 JSMN_ERROR_INVAL = -2,
931 /* The string is not a full JSON packet, more bytes expected */
932 JSMN_ERROR_PART = -3
933};
934typedef struct {
935 jsmntype_t type;
936 ptrdiff_t start;
937 ptrdiff_t end;
938 int size;
939#ifdef JSMN_PARENT_LINKS
940 int parent;
941#endif
942} jsmntok_t;
943typedef struct {
944 size_t pos; /* offset in the JSON string */
945 unsigned int toknext; /* next token to allocate */
946 int toksuper; /* superior token node, e.g parent object or array */
947} jsmn_parser;
948static void jsmn_init(jsmn_parser *parser);
949static int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens);
950/*
951 * -- jsmn.h end --
952 */
953
954
955#ifndef CGLTF_CONSTS
956#define GlbHeaderSize 12
957#define GlbChunkHeaderSize 8
958static const uint32_t GlbVersion = 2;
959static const uint32_t GlbMagic = 0x46546C67;
960static const uint32_t GlbMagicJsonChunk = 0x4E4F534A;
961static const uint32_t GlbMagicBinChunk = 0x004E4942;
962#define CGLTF_CONSTS
963#endif
964
965#ifndef CGLTF_MALLOC
966#define CGLTF_MALLOC(size) malloc(size)
967#endif
968#ifndef CGLTF_FREE
969#define CGLTF_FREE(ptr) free(ptr)
970#endif
971#ifndef CGLTF_ATOI
972#define CGLTF_ATOI(str) atoi(str)
973#endif
974#ifndef CGLTF_ATOF
975#define CGLTF_ATOF(str) atof(str)
976#endif
977#ifndef CGLTF_ATOLL
978#define CGLTF_ATOLL(str) atoll(str)
979#endif
980#ifndef CGLTF_VALIDATE_ENABLE_ASSERTS
981#define CGLTF_VALIDATE_ENABLE_ASSERTS 0
982#endif
983
984static void* cgltf_default_alloc(void* user, cgltf_size size)
985{
986 (void)user;
987 return CGLTF_MALLOC(size);
988}
989
990static void cgltf_default_free(void* user, void* ptr)
991{
992 (void)user;
993 CGLTF_FREE(ptr);
994}
995
996static void* cgltf_calloc(cgltf_options* options, size_t element_size, cgltf_size count)
997{
998 if (SIZE_MAX / element_size < count)
999 {
1000 return NULL;
1001 }
1002 void* result = options->memory.alloc_func(options->memory.user_data, element_size * count);
1003 if (!result)
1004 {
1005 return NULL;
1006 }
1007 memset(result, 0, element_size * count);
1008 return result;
1009}
1010
1011static cgltf_result cgltf_default_file_read(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, const char* path, cgltf_size* size, void** data)
1012{
1013 (void)file_options;
1014 void* (*memory_alloc)(void*, cgltf_size) = memory_options->alloc_func ? memory_options->alloc_func : &cgltf_default_alloc;
1015 void (*memory_free)(void*, void*) = memory_options->free_func ? memory_options->free_func : &cgltf_default_free;
1016
1017 FILE* file = fopen(path, "rb");
1018 if (!file)
1019 {
1020 return cgltf_result_file_not_found;
1021 }
1022
1023 cgltf_size file_size = size ? *size : 0;
1024
1025 if (file_size == 0)
1026 {
1027 fseek(file, 0, SEEK_END);
1028
1029#ifdef _MSC_VER
1030 __int64 length = _ftelli64(file);
1031#else
1032 long length = ftell(file);
1033#endif
1034
1035 if (length < 0)
1036 {
1037 fclose(file);
1038 return cgltf_result_io_error;
1039 }
1040
1041 fseek(file, 0, SEEK_SET);
1042 file_size = (cgltf_size)length;
1043 }
1044
1045 char* file_data = (char*)memory_alloc(memory_options->user_data, file_size);
1046 if (!file_data)
1047 {
1048 fclose(file);
1049 return cgltf_result_out_of_memory;
1050 }
1051
1052 cgltf_size read_size = fread(file_data, 1, file_size, file);
1053
1054 fclose(file);
1055
1056 if (read_size != file_size)
1057 {
1058 memory_free(memory_options->user_data, file_data);
1059 return cgltf_result_io_error;
1060 }
1061
1062 if (size)
1063 {
1064 *size = file_size;
1065 }
1066 if (data)
1067 {
1068 *data = file_data;
1069 }
1070
1071 return cgltf_result_success;
1072}
1073
1074static void cgltf_default_file_release(const struct cgltf_memory_options* memory_options, const struct cgltf_file_options* file_options, void* data)
1075{
1076 (void)file_options;
1077 void (*memfree)(void*, void*) = memory_options->free_func ? memory_options->free_func : &cgltf_default_free;
1078 memfree(memory_options->user_data, data);
1079}
1080
1081static cgltf_result cgltf_parse_json(cgltf_options* options, const uint8_t* json_chunk, cgltf_size size, cgltf_data** out_data);
1082
1083cgltf_result cgltf_parse(const cgltf_options* options, const void* data, cgltf_size size, cgltf_data** out_data)
1084{
1085 if (size < GlbHeaderSize)
1086 {
1087 return cgltf_result_data_too_short;
1088 }
1089
1090 if (options == NULL)
1091 {
1092 return cgltf_result_invalid_options;
1093 }
1094
1095 cgltf_options fixed_options = *options;
1096 if (fixed_options.memory.alloc_func == NULL)
1097 {
1098 fixed_options.memory.alloc_func = &cgltf_default_alloc;
1099 }
1100 if (fixed_options.memory.free_func == NULL)
1101 {
1102 fixed_options.memory.free_func = &cgltf_default_free;
1103 }
1104
1105 uint32_t tmp;
1106 // Magic
1107 memcpy(&tmp, data, 4);
1108 if (tmp != GlbMagic)
1109 {
1110 if (fixed_options.type == cgltf_file_type_invalid)
1111 {
1112 fixed_options.type = cgltf_file_type_gltf;
1113 }
1114 else if (fixed_options.type == cgltf_file_type_glb)
1115 {
1116 return cgltf_result_unknown_format;
1117 }
1118 }
1119
1120 if (fixed_options.type == cgltf_file_type_gltf)
1121 {
1122 cgltf_result json_result = cgltf_parse_json(&fixed_options, (const uint8_t*)data, size, out_data);
1123 if (json_result != cgltf_result_success)
1124 {
1125 return json_result;
1126 }
1127
1128 (*out_data)->file_type = cgltf_file_type_gltf;
1129
1130 return cgltf_result_success;
1131 }
1132
1133 const uint8_t* ptr = (const uint8_t*)data;
1134 // Version
1135 memcpy(&tmp, ptr + 4, 4);
1136 uint32_t version = tmp;
1137 if (version != GlbVersion)
1138 {
1139 return version < GlbVersion ? cgltf_result_legacy_gltf : cgltf_result_unknown_format;
1140 }
1141
1142 // Total length
1143 memcpy(&tmp, ptr + 8, 4);
1144 if (tmp > size)
1145 {
1146 return cgltf_result_data_too_short;
1147 }
1148
1149 const uint8_t* json_chunk = ptr + GlbHeaderSize;
1150
1151 if (GlbHeaderSize + GlbChunkHeaderSize > size)
1152 {
1153 return cgltf_result_data_too_short;
1154 }
1155
1156 // JSON chunk: length
1157 uint32_t json_length;
1158 memcpy(&json_length, json_chunk, 4);
1159 if (json_length > size - GlbHeaderSize - GlbChunkHeaderSize)
1160 {
1161 return cgltf_result_data_too_short;
1162 }
1163
1164 // JSON chunk: magic
1165 memcpy(&tmp, json_chunk + 4, 4);
1166 if (tmp != GlbMagicJsonChunk)
1167 {
1168 return cgltf_result_unknown_format;
1169 }
1170
1171 json_chunk += GlbChunkHeaderSize;
1172
1173 const void* bin = NULL;
1174 cgltf_size bin_size = 0;
1175
1176 if (GlbChunkHeaderSize <= size - GlbHeaderSize - GlbChunkHeaderSize - json_length)
1177 {
1178 // We can read another chunk
1179 const uint8_t* bin_chunk = json_chunk + json_length;
1180
1181 // Bin chunk: length
1182 uint32_t bin_length;
1183 memcpy(&bin_length, bin_chunk, 4);
1184 if (bin_length > size - GlbHeaderSize - GlbChunkHeaderSize - json_length - GlbChunkHeaderSize)
1185 {
1186 return cgltf_result_data_too_short;
1187 }
1188
1189 // Bin chunk: magic
1190 memcpy(&tmp, bin_chunk + 4, 4);
1191 if (tmp != GlbMagicBinChunk)
1192 {
1193 return cgltf_result_unknown_format;
1194 }
1195
1196 bin_chunk += GlbChunkHeaderSize;
1197
1198 bin = bin_chunk;
1199 bin_size = bin_length;
1200 }
1201
1202 cgltf_result json_result = cgltf_parse_json(&fixed_options, json_chunk, json_length, out_data);
1203 if (json_result != cgltf_result_success)
1204 {
1205 return json_result;
1206 }
1207
1208 (*out_data)->file_type = cgltf_file_type_glb;
1209 (*out_data)->bin = bin;
1210 (*out_data)->bin_size = bin_size;
1211
1212 return cgltf_result_success;
1213}
1214
1215cgltf_result cgltf_parse_file(const cgltf_options* options, const char* path, cgltf_data** out_data)
1216{
1217 if (options == NULL)
1218 {
1219 return cgltf_result_invalid_options;
1220 }
1221
1222 cgltf_result (*file_read)(const struct cgltf_memory_options*, const struct cgltf_file_options*, const char*, cgltf_size*, void**) = options->file.read ? options->file.read : &cgltf_default_file_read;
1223 void (*file_release)(const struct cgltf_memory_options*, const struct cgltf_file_options*, void* data) = options->file.release ? options->file.release : cgltf_default_file_release;
1224
1225 void* file_data = NULL;
1226 cgltf_size file_size = 0;
1227 cgltf_result result = file_read(&options->memory, &options->file, path, &file_size, &file_data);
1228 if (result != cgltf_result_success)
1229 {
1230 return result;
1231 }
1232
1233 result = cgltf_parse(options, file_data, file_size, out_data);
1234
1235 if (result != cgltf_result_success)
1236 {
1237 file_release(&options->memory, &options->file, file_data);
1238 return result;
1239 }
1240
1241 (*out_data)->file_data = file_data;
1242
1243 return cgltf_result_success;
1244}
1245
1246static void cgltf_combine_paths(char* path, const char* base, const char* uri)
1247{
1248 const char* s0 = strrchr(base, '/');
1249 const char* s1 = strrchr(base, '\\');
1250 const char* slash = s0 ? (s1 && s1 > s0 ? s1 : s0) : s1;
1251
1252 if (slash)
1253 {
1254 size_t prefix = slash - base + 1;
1255
1256 strncpy(path, base, prefix);
1257 strcpy(path + prefix, uri);
1258 }
1259 else
1260 {
1261 strcpy(path, uri);
1262 }
1263}
1264
1265static cgltf_result cgltf_load_buffer_file(const cgltf_options* options, cgltf_size size, const char* uri, const char* gltf_path, void** out_data)
1266{
1267 void* (*memory_alloc)(void*, cgltf_size) = options->memory.alloc_func ? options->memory.alloc_func : &cgltf_default_alloc;
1268 void (*memory_free)(void*, void*) = options->memory.free_func ? options->memory.free_func : &cgltf_default_free;
1269 cgltf_result (*file_read)(const struct cgltf_memory_options*, const struct cgltf_file_options*, const char*, cgltf_size*, void**) = options->file.read ? options->file.read : &cgltf_default_file_read;
1270
1271 char* path = (char*)memory_alloc(options->memory.user_data, strlen(uri) + strlen(gltf_path) + 1);
1272 if (!path)
1273 {
1274 return cgltf_result_out_of_memory;
1275 }
1276
1277 cgltf_combine_paths(path, gltf_path, uri);
1278
1279 // after combining, the tail of the resulting path is a uri; decode_uri converts it into path
1280 cgltf_decode_uri(path + strlen(path) - strlen(uri));
1281
1282 void* file_data = NULL;
1283 cgltf_result result = file_read(&options->memory, &options->file, path, &size, &file_data);
1284
1285 memory_free(options->memory.user_data, path);
1286
1287 *out_data = (result == cgltf_result_success) ? file_data : NULL;
1288
1289 return result;
1290}
1291
1292cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, cgltf_size size, const char* base64, void** out_data)
1293{
1294 void* (*memory_alloc)(void*, cgltf_size) = options->memory.alloc_func ? options->memory.alloc_func : &cgltf_default_alloc;
1295 void (*memory_free)(void*, void*) = options->memory.free_func ? options->memory.free_func : &cgltf_default_free;
1296
1297 unsigned char* data = (unsigned char*)memory_alloc(options->memory.user_data, size);
1298 if (!data)
1299 {
1300 return cgltf_result_out_of_memory;
1301 }
1302
1303 unsigned int buffer = 0;
1304 unsigned int buffer_bits = 0;
1305
1306 for (cgltf_size i = 0; i < size; ++i)
1307 {
1308 while (buffer_bits < 8)
1309 {
1310 char ch = *base64++;
1311
1312 int index =
1313 (unsigned)(ch - 'A') < 26 ? (ch - 'A') :
1314 (unsigned)(ch - 'a') < 26 ? (ch - 'a') + 26 :
1315 (unsigned)(ch - '0') < 10 ? (ch - '0') + 52 :
1316 ch == '+' ? 62 :
1317 ch == '/' ? 63 :
1318 -1;
1319
1320 if (index < 0)
1321 {
1322 memory_free(options->memory.user_data, data);
1323 return cgltf_result_io_error;
1324 }
1325
1326 buffer = (buffer << 6) | index;
1327 buffer_bits += 6;
1328 }
1329
1330 data[i] = (unsigned char)(buffer >> (buffer_bits - 8));
1331 buffer_bits -= 8;
1332 }
1333
1334 *out_data = data;
1335
1336 return cgltf_result_success;
1337}
1338
1339static int cgltf_unhex(char ch)
1340{
1341 return
1342 (unsigned)(ch - '0') < 10 ? (ch - '0') :
1343 (unsigned)(ch - 'A') < 6 ? (ch - 'A') + 10 :
1344 (unsigned)(ch - 'a') < 6 ? (ch - 'a') + 10 :
1345 -1;
1346}
1347
1348cgltf_size cgltf_decode_string(char* string)
1349{
1350 char* read = string + strcspn(string, "\\");
1351 if (*read == 0)
1352 {
1353 return read - string;
1354 }
1355 char* write = string;
1356 char* last = string;
1357
1358 for (;;)
1359 {
1360 // Copy characters since last escaped sequence
1361 cgltf_size written = read - last;
1362 memmove(write, last, written);
1363 write += written;
1364
1365 if (*read++ == 0)
1366 {
1367 break;
1368 }
1369
1370 // jsmn already checked that all escape sequences are valid
1371 switch (*read++)
1372 {
1373 case '\"': *write++ = '\"'; break;
1374 case '/': *write++ = '/'; break;
1375 case '\\': *write++ = '\\'; break;
1376 case 'b': *write++ = '\b'; break;
1377 case 'f': *write++ = '\f'; break;
1378 case 'r': *write++ = '\r'; break;
1379 case 'n': *write++ = '\n'; break;
1380 case 't': *write++ = '\t'; break;
1381 case 'u':
1382 {
1383 // UCS-2 codepoint \uXXXX to UTF-8
1384 int character = 0;
1385 for (cgltf_size i = 0; i < 4; ++i)
1386 {
1387 character = (character << 4) + cgltf_unhex(*read++);
1388 }
1389
1390 if (character <= 0x7F)
1391 {
1392 *write++ = character & 0xFF;
1393 }
1394 else if (character <= 0x7FF)
1395 {
1396 *write++ = 0xC0 | ((character >> 6) & 0xFF);
1397 *write++ = 0x80 | (character & 0x3F);
1398 }
1399 else
1400 {
1401 *write++ = 0xE0 | ((character >> 12) & 0xFF);
1402 *write++ = 0x80 | ((character >> 6) & 0x3F);
1403 *write++ = 0x80 | (character & 0x3F);
1404 }
1405 break;
1406 }
1407 default:
1408 break;
1409 }
1410
1411 last = read;
1412 read += strcspn(read, "\\");
1413 }
1414
1415 *write = 0;
1416 return write - string;
1417}
1418
1419cgltf_size cgltf_decode_uri(char* uri)
1420{
1421 char* write = uri;
1422 char* i = uri;
1423
1424 while (*i)
1425 {
1426 if (*i == '%')
1427 {
1428 int ch1 = cgltf_unhex(i[1]);
1429
1430 if (ch1 >= 0)
1431 {
1432 int ch2 = cgltf_unhex(i[2]);
1433
1434 if (ch2 >= 0)
1435 {
1436 *write++ = (char)(ch1 * 16 + ch2);
1437 i += 3;
1438 continue;
1439 }
1440 }
1441 }
1442
1443 *write++ = *i++;
1444 }
1445
1446 *write = 0;
1447 return write - uri;
1448}
1449
1450cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data, const char* gltf_path)
1451{
1452 if (options == NULL)
1453 {
1454 return cgltf_result_invalid_options;
1455 }
1456
1457 if (data->buffers_count && data->buffers[0].data == NULL && data->buffers[0].uri == NULL && data->bin)
1458 {
1459 if (data->bin_size < data->buffers[0].size)
1460 {
1461 return cgltf_result_data_too_short;
1462 }
1463
1464 data->buffers[0].data = (void*)data->bin;
1465 data->buffers[0].data_free_method = cgltf_data_free_method_none;
1466 }
1467
1468 for (cgltf_size i = 0; i < data->buffers_count; ++i)
1469 {
1470 if (data->buffers[i].data)
1471 {
1472 continue;
1473 }
1474
1475 const char* uri = data->buffers[i].uri;
1476
1477 if (uri == NULL)
1478 {
1479 continue;
1480 }
1481
1482 if (strncmp(uri, "data:", 5) == 0)
1483 {
1484 const char* comma = strchr(uri, ',');
1485
1486 if (comma && comma - uri >= 7 && strncmp(comma - 7, ";base64", 7) == 0)
1487 {
1488 cgltf_result res = cgltf_load_buffer_base64(options, data->buffers[i].size, comma + 1, &data->buffers[i].data);
1489 data->buffers[i].data_free_method = cgltf_data_free_method_memory_free;
1490
1491 if (res != cgltf_result_success)
1492 {
1493 return res;
1494 }
1495 }
1496 else
1497 {
1498 return cgltf_result_unknown_format;
1499 }
1500 }
1501 else if (strstr(uri, "://") == NULL && gltf_path)
1502 {
1503 cgltf_result res = cgltf_load_buffer_file(options, data->buffers[i].size, uri, gltf_path, &data->buffers[i].data);
1504 data->buffers[i].data_free_method = cgltf_data_free_method_file_release;
1505
1506 if (res != cgltf_result_success)
1507 {
1508 return res;
1509 }
1510 }
1511 else
1512 {
1513 return cgltf_result_unknown_format;
1514 }
1515 }
1516
1517 return cgltf_result_success;
1518}
1519
1520static cgltf_size cgltf_calc_index_bound(cgltf_buffer_view* buffer_view, cgltf_size offset, cgltf_component_type component_type, cgltf_size count)
1521{
1522 char* data = (char*)buffer_view->buffer->data + offset + buffer_view->offset;
1523 cgltf_size bound = 0;
1524
1525 switch (component_type)
1526 {
1527 case cgltf_component_type_r_8u:
1528 for (size_t i = 0; i < count; ++i)
1529 {
1530 cgltf_size v = ((unsigned char*)data)[i];
1531 bound = bound > v ? bound : v;
1532 }
1533 break;
1534
1535 case cgltf_component_type_r_16u:
1536 for (size_t i = 0; i < count; ++i)
1537 {
1538 cgltf_size v = ((unsigned short*)data)[i];
1539 bound = bound > v ? bound : v;
1540 }
1541 break;
1542
1543 case cgltf_component_type_r_32u:
1544 for (size_t i = 0; i < count; ++i)
1545 {
1546 cgltf_size v = ((unsigned int*)data)[i];
1547 bound = bound > v ? bound : v;
1548 }
1549 break;
1550
1551 default:
1552 ;
1553 }
1554
1555 return bound;
1556}
1557
1558#if CGLTF_VALIDATE_ENABLE_ASSERTS
1559#define CGLTF_ASSERT_IF(cond, result) assert(!(cond)); if (cond) return result;
1560#else
1561#define CGLTF_ASSERT_IF(cond, result) if (cond) return result;
1562#endif
1563
1564cgltf_result cgltf_validate(cgltf_data* data)
1565{
1566 for (cgltf_size i = 0; i < data->accessors_count; ++i)
1567 {
1568 cgltf_accessor* accessor = &data->accessors[i];
1569
1570 CGLTF_ASSERT_IF(data->accessors[i].component_type == cgltf_component_type_invalid, cgltf_result_invalid_gltf);
1571 CGLTF_ASSERT_IF(data->accessors[i].type == cgltf_type_invalid, cgltf_result_invalid_gltf);
1572
1573 cgltf_size element_size = cgltf_calc_size(accessor->type, accessor->component_type);
1574
1575 if (accessor->buffer_view)
1576 {
1577 cgltf_size req_size = accessor->offset + accessor->stride * (accessor->count - 1) + element_size;
1578
1579 CGLTF_ASSERT_IF(accessor->buffer_view->size < req_size, cgltf_result_data_too_short);
1580 }
1581
1582 if (accessor->is_sparse)
1583 {
1584 cgltf_accessor_sparse* sparse = &accessor->sparse;
1585
1586 cgltf_size indices_component_size = cgltf_component_size(sparse->indices_component_type);
1587 cgltf_size indices_req_size = sparse->indices_byte_offset + indices_component_size * sparse->count;
1588 cgltf_size values_req_size = sparse->values_byte_offset + element_size * sparse->count;
1589
1590 CGLTF_ASSERT_IF(sparse->indices_buffer_view->size < indices_req_size ||
1591 sparse->values_buffer_view->size < values_req_size, cgltf_result_data_too_short);
1592
1593 CGLTF_ASSERT_IF(sparse->indices_component_type != cgltf_component_type_r_8u &&
1594 sparse->indices_component_type != cgltf_component_type_r_16u &&
1595 sparse->indices_component_type != cgltf_component_type_r_32u, cgltf_result_invalid_gltf);
1596
1597 if (sparse->indices_buffer_view->buffer->data)
1598 {
1599 cgltf_size index_bound = cgltf_calc_index_bound(sparse->indices_buffer_view, sparse->indices_byte_offset, sparse->indices_component_type, sparse->count);
1600
1601 CGLTF_ASSERT_IF(index_bound >= accessor->count, cgltf_result_data_too_short);
1602 }
1603 }
1604 }
1605
1606 for (cgltf_size i = 0; i < data->buffer_views_count; ++i)
1607 {
1608 cgltf_size req_size = data->buffer_views[i].offset + data->buffer_views[i].size;
1609
1610 CGLTF_ASSERT_IF(data->buffer_views[i].buffer && data->buffer_views[i].buffer->size < req_size, cgltf_result_data_too_short);
1611
1612 if (data->buffer_views[i].has_meshopt_compression)
1613 {
1614 cgltf_meshopt_compression* mc = &data->buffer_views[i].meshopt_compression;
1615
1616 CGLTF_ASSERT_IF(mc->buffer == NULL || mc->buffer->size < mc->offset + mc->size, cgltf_result_data_too_short);
1617
1618 CGLTF_ASSERT_IF(data->buffer_views[i].stride && mc->stride != data->buffer_views[i].stride, cgltf_result_invalid_gltf);
1619
1620 CGLTF_ASSERT_IF(data->buffer_views[i].size != mc->stride * mc->count, cgltf_result_invalid_gltf);
1621
1622 CGLTF_ASSERT_IF(mc->mode == cgltf_meshopt_compression_mode_invalid, cgltf_result_invalid_gltf);
1623
1624 CGLTF_ASSERT_IF(mc->mode == cgltf_meshopt_compression_mode_attributes && !(mc->stride % 4 == 0 && mc->stride <= 256), cgltf_result_invalid_gltf);
1625
1626 CGLTF_ASSERT_IF(mc->mode == cgltf_meshopt_compression_mode_triangles && mc->count % 3 != 0, cgltf_result_invalid_gltf);
1627
1628 CGLTF_ASSERT_IF((mc->mode == cgltf_meshopt_compression_mode_triangles || mc->mode == cgltf_meshopt_compression_mode_indices) && mc->stride != 2 && mc->stride != 4, cgltf_result_invalid_gltf);
1629
1630 CGLTF_ASSERT_IF((mc->mode == cgltf_meshopt_compression_mode_triangles || mc->mode == cgltf_meshopt_compression_mode_indices) && mc->filter != cgltf_meshopt_compression_filter_none, cgltf_result_invalid_gltf);
1631
1632 CGLTF_ASSERT_IF(mc->filter == cgltf_meshopt_compression_filter_octahedral && mc->stride != 4 && mc->stride != 8, cgltf_result_invalid_gltf);
1633
1634 CGLTF_ASSERT_IF(mc->filter == cgltf_meshopt_compression_filter_quaternion && mc->stride != 8, cgltf_result_invalid_gltf);
1635 }
1636 }
1637
1638 for (cgltf_size i = 0; i < data->meshes_count; ++i)
1639 {
1640 if (data->meshes[i].weights)
1641 {
1642 CGLTF_ASSERT_IF(data->meshes[i].primitives_count && data->meshes[i].primitives[0].targets_count != data->meshes[i].weights_count, cgltf_result_invalid_gltf);
1643 }
1644
1645 if (data->meshes[i].target_names)
1646 {
1647 CGLTF_ASSERT_IF(data->meshes[i].primitives_count && data->meshes[i].primitives[0].targets_count != data->meshes[i].target_names_count, cgltf_result_invalid_gltf);
1648 }
1649
1650 for (cgltf_size j = 0; j < data->meshes[i].primitives_count; ++j)
1651 {
1652 CGLTF_ASSERT_IF(data->meshes[i].primitives[j].type == cgltf_primitive_type_invalid, cgltf_result_invalid_gltf);
1653 CGLTF_ASSERT_IF(data->meshes[i].primitives[j].targets_count != data->meshes[i].primitives[0].targets_count, cgltf_result_invalid_gltf);
1654
1655 CGLTF_ASSERT_IF(data->meshes[i].primitives[j].attributes_count == 0, cgltf_result_invalid_gltf);
1656
1657 cgltf_accessor* first = data->meshes[i].primitives[j].attributes[0].data;
1658
1659 CGLTF_ASSERT_IF(first->count == 0, cgltf_result_invalid_gltf);
1660
1661 for (cgltf_size k = 0; k < data->meshes[i].primitives[j].attributes_count; ++k)
1662 {
1663 CGLTF_ASSERT_IF(data->meshes[i].primitives[j].attributes[k].data->count != first->count, cgltf_result_invalid_gltf);
1664 }
1665
1666 for (cgltf_size k = 0; k < data->meshes[i].primitives[j].targets_count; ++k)
1667 {
1668 for (cgltf_size m = 0; m < data->meshes[i].primitives[j].targets[k].attributes_count; ++m)
1669 {
1670 CGLTF_ASSERT_IF(data->meshes[i].primitives[j].targets[k].attributes[m].data->count != first->count, cgltf_result_invalid_gltf);
1671 }
1672 }
1673
1674 cgltf_accessor* indices = data->meshes[i].primitives[j].indices;
1675
1676 CGLTF_ASSERT_IF(indices &&
1677 indices->component_type != cgltf_component_type_r_8u &&
1678 indices->component_type != cgltf_component_type_r_16u &&
1679 indices->component_type != cgltf_component_type_r_32u, cgltf_result_invalid_gltf);
1680
1681 CGLTF_ASSERT_IF(indices && indices->type != cgltf_type_scalar, cgltf_result_invalid_gltf);
1682 CGLTF_ASSERT_IF(indices && indices->stride != cgltf_component_size(indices->component_type), cgltf_result_invalid_gltf);
1683
1684 if (indices && indices->buffer_view && indices->buffer_view->buffer->data)
1685 {
1686 cgltf_size index_bound = cgltf_calc_index_bound(indices->buffer_view, indices->offset, indices->component_type, indices->count);
1687
1688 CGLTF_ASSERT_IF(index_bound >= first->count, cgltf_result_data_too_short);
1689 }
1690
1691 for (cgltf_size k = 0; k < data->meshes[i].primitives[j].mappings_count; ++k)
1692 {
1693 CGLTF_ASSERT_IF(data->meshes[i].primitives[j].mappings[k].variant >= data->variants_count, cgltf_result_invalid_gltf);
1694 }
1695 }
1696 }
1697
1698 for (cgltf_size i = 0; i < data->nodes_count; ++i)
1699 {
1700 if (data->nodes[i].weights && data->nodes[i].mesh)
1701 {
1702 CGLTF_ASSERT_IF(data->nodes[i].mesh->primitives_count && data->nodes[i].mesh->primitives[0].targets_count != data->nodes[i].weights_count, cgltf_result_invalid_gltf);
1703 }
1704
1705 if (data->nodes[i].has_mesh_gpu_instancing)
1706 {
1707 CGLTF_ASSERT_IF(data->nodes[i].mesh == NULL, cgltf_result_invalid_gltf);
1708 CGLTF_ASSERT_IF(data->nodes[i].mesh_gpu_instancing.attributes_count == 0, cgltf_result_invalid_gltf);
1709
1710 cgltf_accessor* first = data->nodes[i].mesh_gpu_instancing.attributes[0].data;
1711
1712 for (cgltf_size k = 0; k < data->nodes[i].mesh_gpu_instancing.attributes_count; ++k)
1713 {
1714 CGLTF_ASSERT_IF(data->nodes[i].mesh_gpu_instancing.attributes[k].data->count != first->count, cgltf_result_invalid_gltf);
1715 }
1716 }
1717 }
1718
1719 for (cgltf_size i = 0; i < data->nodes_count; ++i)
1720 {
1721 cgltf_node* p1 = data->nodes[i].parent;
1722 cgltf_node* p2 = p1 ? p1->parent : NULL;
1723
1724 while (p1 && p2)
1725 {
1726 CGLTF_ASSERT_IF(p1 == p2, cgltf_result_invalid_gltf);
1727
1728 p1 = p1->parent;
1729 p2 = p2->parent ? p2->parent->parent : NULL;
1730 }
1731 }
1732
1733 for (cgltf_size i = 0; i < data->scenes_count; ++i)
1734 {
1735 for (cgltf_size j = 0; j < data->scenes[i].nodes_count; ++j)
1736 {
1737 CGLTF_ASSERT_IF(data->scenes[i].nodes[j]->parent, cgltf_result_invalid_gltf);
1738 }
1739 }
1740
1741 for (cgltf_size i = 0; i < data->animations_count; ++i)
1742 {
1743 for (cgltf_size j = 0; j < data->animations[i].channels_count; ++j)
1744 {
1745 cgltf_animation_channel* channel = &data->animations[i].channels[j];
1746
1747 if (!channel->target_node)
1748 {
1749 continue;
1750 }
1751
1752 cgltf_size components = 1;
1753
1754 if (channel->target_path == cgltf_animation_path_type_weights)
1755 {
1756 CGLTF_ASSERT_IF(!channel->target_node->mesh || !channel->target_node->mesh->primitives_count, cgltf_result_invalid_gltf);
1757
1758 components = channel->target_node->mesh->primitives[0].targets_count;
1759 }
1760
1761 cgltf_size values = channel->sampler->interpolation == cgltf_interpolation_type_cubic_spline ? 3 : 1;
1762
1763 CGLTF_ASSERT_IF(channel->sampler->input->count * components * values != channel->sampler->output->count, cgltf_result_invalid_gltf);
1764 }
1765 }
1766
1767 for (cgltf_size i = 0; i < data->variants_count; ++i)
1768 {
1769 CGLTF_ASSERT_IF(!data->variants[i].name, cgltf_result_invalid_gltf);
1770 }
1771
1772 return cgltf_result_success;
1773}
1774
1775cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* extras, char* dest, cgltf_size* dest_size)
1776{
1777 cgltf_size json_size = extras->end_offset - extras->start_offset;
1778
1779 if (!dest)
1780 {
1781 if (dest_size)
1782 {
1783 *dest_size = json_size + 1;
1784 return cgltf_result_success;
1785 }
1786 return cgltf_result_invalid_options;
1787 }
1788
1789 if (*dest_size + 1 < json_size)
1790 {
1791 strncpy(dest, data->json + extras->start_offset, *dest_size - 1);
1792 dest[*dest_size - 1] = 0;
1793 }
1794 else
1795 {
1796 strncpy(dest, data->json + extras->start_offset, json_size);
1797 dest[json_size] = 0;
1798 }
1799
1800 return cgltf_result_success;
1801}
1802
1803static void cgltf_free_extras(cgltf_data* data, cgltf_extras* extras)
1804{
1805 data->memory.free_func(data->memory.user_data, extras->data);
1806}
1807
1808static void cgltf_free_extensions(cgltf_data* data, cgltf_extension* extensions, cgltf_size extensions_count)
1809{
1810 for (cgltf_size i = 0; i < extensions_count; ++i)
1811 {
1812 data->memory.free_func(data->memory.user_data, extensions[i].name);
1813 data->memory.free_func(data->memory.user_data, extensions[i].data);
1814 }
1815 data->memory.free_func(data->memory.user_data, extensions);
1816}
1817
1818void cgltf_free(cgltf_data* data)
1819{
1820 if (!data)
1821 {
1822 return;
1823 }
1824
1825 void (*file_release)(const struct cgltf_memory_options*, const struct cgltf_file_options*, void* data) = data->file.release ? data->file.release : cgltf_default_file_release;
1826
1827 data->memory.free_func(data->memory.user_data, data->asset.copyright);
1828 data->memory.free_func(data->memory.user_data, data->asset.generator);
1829 data->memory.free_func(data->memory.user_data, data->asset.version);
1830 data->memory.free_func(data->memory.user_data, data->asset.min_version);
1831
1832 cgltf_free_extensions(data, data->asset.extensions, data->asset.extensions_count);
1833 cgltf_free_extras(data, &data->asset.extras);
1834
1835 for (cgltf_size i = 0; i < data->accessors_count; ++i)
1836 {
1837 data->memory.free_func(data->memory.user_data, data->accessors[i].name);
1838
1839 cgltf_free_extensions(data, data->accessors[i].extensions, data->accessors[i].extensions_count);
1840 cgltf_free_extras(data, &data->accessors[i].extras);
1841 }
1842 data->memory.free_func(data->memory.user_data, data->accessors);
1843
1844 for (cgltf_size i = 0; i < data->buffer_views_count; ++i)
1845 {
1846 data->memory.free_func(data->memory.user_data, data->buffer_views[i].name);
1847 data->memory.free_func(data->memory.user_data, data->buffer_views[i].data);
1848
1849 cgltf_free_extensions(data, data->buffer_views[i].extensions, data->buffer_views[i].extensions_count);
1850 cgltf_free_extras(data, &data->buffer_views[i].extras);
1851 }
1852 data->memory.free_func(data->memory.user_data, data->buffer_views);
1853
1854 for (cgltf_size i = 0; i < data->buffers_count; ++i)
1855 {
1856 data->memory.free_func(data->memory.user_data, data->buffers[i].name);
1857
1858 if (data->buffers[i].data_free_method == cgltf_data_free_method_file_release)
1859 {
1860 file_release(&data->memory, &data->file, data->buffers[i].data);
1861 }
1862 else if (data->buffers[i].data_free_method == cgltf_data_free_method_memory_free)
1863 {
1864 data->memory.free_func(data->memory.user_data, data->buffers[i].data);
1865 }
1866
1867 data->memory.free_func(data->memory.user_data, data->buffers[i].uri);
1868
1869 cgltf_free_extensions(data, data->buffers[i].extensions, data->buffers[i].extensions_count);
1870 cgltf_free_extras(data, &data->buffers[i].extras);
1871 }
1872 data->memory.free_func(data->memory.user_data, data->buffers);
1873
1874 for (cgltf_size i = 0; i < data->meshes_count; ++i)
1875 {
1876 data->memory.free_func(data->memory.user_data, data->meshes[i].name);
1877
1878 for (cgltf_size j = 0; j < data->meshes[i].primitives_count; ++j)
1879 {
1880 for (cgltf_size k = 0; k < data->meshes[i].primitives[j].attributes_count; ++k)
1881 {
1882 data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].attributes[k].name);
1883 }
1884
1885 data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].attributes);
1886
1887 for (cgltf_size k = 0; k < data->meshes[i].primitives[j].targets_count; ++k)
1888 {
1889 for (cgltf_size m = 0; m < data->meshes[i].primitives[j].targets[k].attributes_count; ++m)
1890 {
1891 data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].targets[k].attributes[m].name);
1892 }
1893
1894 data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].targets[k].attributes);
1895 }
1896
1897 data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].targets);
1898
1899 if (data->meshes[i].primitives[j].has_draco_mesh_compression)
1900 {
1901 for (cgltf_size k = 0; k < data->meshes[i].primitives[j].draco_mesh_compression.attributes_count; ++k)
1902 {
1903 data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].draco_mesh_compression.attributes[k].name);
1904 }
1905
1906 data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].draco_mesh_compression.attributes);
1907 }
1908
1909 for (cgltf_size k = 0; k < data->meshes[i].primitives[j].mappings_count; ++k)
1910 {
1911 cgltf_free_extras(data, &data->meshes[i].primitives[j].mappings[k].extras);
1912 }
1913
1914 data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].mappings);
1915
1916 cgltf_free_extensions(data, data->meshes[i].primitives[j].extensions, data->meshes[i].primitives[j].extensions_count);
1917 cgltf_free_extras(data, &data->meshes[i].primitives[j].extras);
1918 }
1919
1920 data->memory.free_func(data->memory.user_data, data->meshes[i].primitives);
1921 data->memory.free_func(data->memory.user_data, data->meshes[i].weights);
1922
1923 for (cgltf_size j = 0; j < data->meshes[i].target_names_count; ++j)
1924 {
1925 data->memory.free_func(data->memory.user_data, data->meshes[i].target_names[j]);
1926 }
1927
1928 cgltf_free_extensions(data, data->meshes[i].extensions, data->meshes[i].extensions_count);
1929 cgltf_free_extras(data, &data->meshes[i].extras);
1930
1931 data->memory.free_func(data->memory.user_data, data->meshes[i].target_names);
1932 }
1933
1934 data->memory.free_func(data->memory.user_data, data->meshes);
1935
1936 for (cgltf_size i = 0; i < data->materials_count; ++i)
1937 {
1938 data->memory.free_func(data->memory.user_data, data->materials[i].name);
1939
1940 cgltf_free_extensions(data, data->materials[i].extensions, data->materials[i].extensions_count);
1941 cgltf_free_extras(data, &data->materials[i].extras);
1942 }
1943
1944 data->memory.free_func(data->memory.user_data, data->materials);
1945
1946 for (cgltf_size i = 0; i < data->images_count; ++i)
1947 {
1948 data->memory.free_func(data->memory.user_data, data->images[i].name);
1949 data->memory.free_func(data->memory.user_data, data->images[i].uri);
1950 data->memory.free_func(data->memory.user_data, data->images[i].mime_type);
1951
1952 cgltf_free_extensions(data, data->images[i].extensions, data->images[i].extensions_count);
1953 cgltf_free_extras(data, &data->images[i].extras);
1954 }
1955
1956 data->memory.free_func(data->memory.user_data, data->images);
1957
1958 for (cgltf_size i = 0; i < data->textures_count; ++i)
1959 {
1960 data->memory.free_func(data->memory.user_data, data->textures[i].name);
1961
1962 cgltf_free_extensions(data, data->textures[i].extensions, data->textures[i].extensions_count);
1963 cgltf_free_extras(data, &data->textures[i].extras);
1964 }
1965
1966 data->memory.free_func(data->memory.user_data, data->textures);
1967
1968 for (cgltf_size i = 0; i < data->samplers_count; ++i)
1969 {
1970 data->memory.free_func(data->memory.user_data, data->samplers[i].name);
1971
1972 cgltf_free_extensions(data, data->samplers[i].extensions, data->samplers[i].extensions_count);
1973 cgltf_free_extras(data, &data->samplers[i].extras);
1974 }
1975
1976 data->memory.free_func(data->memory.user_data, data->samplers);
1977
1978 for (cgltf_size i = 0; i < data->skins_count; ++i)
1979 {
1980 data->memory.free_func(data->memory.user_data, data->skins[i].name);
1981 data->memory.free_func(data->memory.user_data, data->skins[i].joints);
1982
1983 cgltf_free_extensions(data, data->skins[i].extensions, data->skins[i].extensions_count);
1984 cgltf_free_extras(data, &data->skins[i].extras);
1985 }
1986
1987 data->memory.free_func(data->memory.user_data, data->skins);
1988
1989 for (cgltf_size i = 0; i < data->cameras_count; ++i)
1990 {
1991 data->memory.free_func(data->memory.user_data, data->cameras[i].name);
1992
1993 if (data->cameras[i].type == cgltf_camera_type_perspective)
1994 {
1995 cgltf_free_extras(data, &data->cameras[i].data.perspective.extras);
1996 }
1997 else if (data->cameras[i].type == cgltf_camera_type_orthographic)
1998 {
1999 cgltf_free_extras(data, &data->cameras[i].data.orthographic.extras);
2000 }
2001
2002 cgltf_free_extensions(data, data->cameras[i].extensions, data->cameras[i].extensions_count);
2003 cgltf_free_extras(data, &data->cameras[i].extras);
2004 }
2005
2006 data->memory.free_func(data->memory.user_data, data->cameras);
2007
2008 for (cgltf_size i = 0; i < data->lights_count; ++i)
2009 {
2010 data->memory.free_func(data->memory.user_data, data->lights[i].name);
2011
2012 cgltf_free_extras(data, &data->lights[i].extras);
2013 }
2014
2015 data->memory.free_func(data->memory.user_data, data->lights);
2016
2017 for (cgltf_size i = 0; i < data->nodes_count; ++i)
2018 {
2019 data->memory.free_func(data->memory.user_data, data->nodes[i].name);
2020 data->memory.free_func(data->memory.user_data, data->nodes[i].children);
2021 data->memory.free_func(data->memory.user_data, data->nodes[i].weights);
2022
2023 if (data->nodes[i].has_mesh_gpu_instancing)
2024 {
2025 for (cgltf_size j = 0; j < data->nodes[i].mesh_gpu_instancing.attributes_count; ++j)
2026 {
2027 data->memory.free_func(data->memory.user_data, data->nodes[i].mesh_gpu_instancing.attributes[j].name);
2028 }
2029
2030 data->memory.free_func(data->memory.user_data, data->nodes[i].mesh_gpu_instancing.attributes);
2031 }
2032
2033 cgltf_free_extensions(data, data->nodes[i].extensions, data->nodes[i].extensions_count);
2034 cgltf_free_extras(data, &data->nodes[i].extras);
2035 }
2036
2037 data->memory.free_func(data->memory.user_data, data->nodes);
2038
2039 for (cgltf_size i = 0; i < data->scenes_count; ++i)
2040 {
2041 data->memory.free_func(data->memory.user_data, data->scenes[i].name);
2042 data->memory.free_func(data->memory.user_data, data->scenes[i].nodes);
2043
2044 cgltf_free_extensions(data, data->scenes[i].extensions, data->scenes[i].extensions_count);
2045 cgltf_free_extras(data, &data->scenes[i].extras);
2046 }
2047
2048 data->memory.free_func(data->memory.user_data, data->scenes);
2049
2050 for (cgltf_size i = 0; i < data->animations_count; ++i)
2051 {
2052 data->memory.free_func(data->memory.user_data, data->animations[i].name);
2053 for (cgltf_size j = 0; j < data->animations[i].samplers_count; ++j)
2054 {
2055 cgltf_free_extensions(data, data->animations[i].samplers[j].extensions, data->animations[i].samplers[j].extensions_count);
2056 cgltf_free_extras(data, &data->animations[i].samplers[j].extras);
2057 }
2058 data->memory.free_func(data->memory.user_data, data->animations[i].samplers);
2059
2060 for (cgltf_size j = 0; j < data->animations[i].channels_count; ++j)
2061 {
2062 cgltf_free_extensions(data, data->animations[i].channels[j].extensions, data->animations[i].channels[j].extensions_count);
2063 cgltf_free_extras(data, &data->animations[i].channels[j].extras);
2064 }
2065 data->memory.free_func(data->memory.user_data, data->animations[i].channels);
2066
2067 cgltf_free_extensions(data, data->animations[i].extensions, data->animations[i].extensions_count);
2068 cgltf_free_extras(data, &data->animations[i].extras);
2069 }
2070
2071 data->memory.free_func(data->memory.user_data, data->animations);
2072
2073 for (cgltf_size i = 0; i < data->variants_count; ++i)
2074 {
2075 data->memory.free_func(data->memory.user_data, data->variants[i].name);
2076
2077 cgltf_free_extras(data, &data->variants[i].extras);
2078 }
2079
2080 data->memory.free_func(data->memory.user_data, data->variants);
2081
2082 cgltf_free_extensions(data, data->data_extensions, data->data_extensions_count);
2083 cgltf_free_extras(data, &data->extras);
2084
2085 for (cgltf_size i = 0; i < data->extensions_used_count; ++i)
2086 {
2087 data->memory.free_func(data->memory.user_data, data->extensions_used[i]);
2088 }
2089
2090 data->memory.free_func(data->memory.user_data, data->extensions_used);
2091
2092 for (cgltf_size i = 0; i < data->extensions_required_count; ++i)
2093 {
2094 data->memory.free_func(data->memory.user_data, data->extensions_required[i]);
2095 }
2096
2097 data->memory.free_func(data->memory.user_data, data->extensions_required);
2098
2099 file_release(&data->memory, &data->file, data->file_data);
2100
2101 data->memory.free_func(data->memory.user_data, data);
2102}
2103
2104void cgltf_node_transform_local(const cgltf_node* node, cgltf_float* out_matrix)
2105{
2106 cgltf_float* lm = out_matrix;
2107
2108 if (node->has_matrix)
2109 {
2110 memcpy(lm, node->matrix, sizeof(float) * 16);
2111 }
2112 else
2113 {
2114 float tx = node->translation[0];
2115 float ty = node->translation[1];
2116 float tz = node->translation[2];
2117
2118 float qx = node->rotation[0];
2119 float qy = node->rotation[1];
2120 float qz = node->rotation[2];
2121 float qw = node->rotation[3];
2122
2123 float sx = node->scale[0];
2124 float sy = node->scale[1];
2125 float sz = node->scale[2];
2126
2127 lm[0] = (1 - 2 * qy*qy - 2 * qz*qz) * sx;
2128 lm[1] = (2 * qx*qy + 2 * qz*qw) * sx;
2129 lm[2] = (2 * qx*qz - 2 * qy*qw) * sx;
2130 lm[3] = 0.f;
2131
2132 lm[4] = (2 * qx*qy - 2 * qz*qw) * sy;
2133 lm[5] = (1 - 2 * qx*qx - 2 * qz*qz) * sy;
2134 lm[6] = (2 * qy*qz + 2 * qx*qw) * sy;
2135 lm[7] = 0.f;
2136
2137 lm[8] = (2 * qx*qz + 2 * qy*qw) * sz;
2138 lm[9] = (2 * qy*qz - 2 * qx*qw) * sz;
2139 lm[10] = (1 - 2 * qx*qx - 2 * qy*qy) * sz;
2140 lm[11] = 0.f;
2141
2142 lm[12] = tx;
2143 lm[13] = ty;
2144 lm[14] = tz;
2145 lm[15] = 1.f;
2146 }
2147}
2148
2149void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix)
2150{
2151 cgltf_float* lm = out_matrix;
2152 cgltf_node_transform_local(node, lm);
2153
2154 const cgltf_node* parent = node->parent;
2155
2156 while (parent)
2157 {
2158 float pm[16];
2159 cgltf_node_transform_local(parent, pm);
2160
2161 for (int i = 0; i < 4; ++i)
2162 {
2163 float l0 = lm[i * 4 + 0];
2164 float l1 = lm[i * 4 + 1];
2165 float l2 = lm[i * 4 + 2];
2166
2167 float r0 = l0 * pm[0] + l1 * pm[4] + l2 * pm[8];
2168 float r1 = l0 * pm[1] + l1 * pm[5] + l2 * pm[9];
2169 float r2 = l0 * pm[2] + l1 * pm[6] + l2 * pm[10];
2170
2171 lm[i * 4 + 0] = r0;
2172 lm[i * 4 + 1] = r1;
2173 lm[i * 4 + 2] = r2;
2174 }
2175
2176 lm[12] += pm[12];
2177 lm[13] += pm[13];
2178 lm[14] += pm[14];
2179
2180 parent = parent->parent;
2181 }
2182}
2183
2184static cgltf_ssize cgltf_component_read_integer(const void* in, cgltf_component_type component_type)
2185{
2186 switch (component_type)
2187 {
2188 case cgltf_component_type_r_16:
2189 return *((const int16_t*) in);
2190 case cgltf_component_type_r_16u:
2191 return *((const uint16_t*) in);
2192 case cgltf_component_type_r_32u:
2193 return *((const uint32_t*) in);
2194 case cgltf_component_type_r_8:
2195 return *((const int8_t*) in);
2196 case cgltf_component_type_r_8u:
2197 return *((const uint8_t*) in);
2198 default:
2199 return 0;
2200 }
2201}
2202
2203static cgltf_size cgltf_component_read_index(const void* in, cgltf_component_type component_type)
2204{
2205 switch (component_type)
2206 {
2207 case cgltf_component_type_r_16u:
2208 return *((const uint16_t*) in);
2209 case cgltf_component_type_r_32u:
2210 return *((const uint32_t*) in);
2211 case cgltf_component_type_r_8u:
2212 return *((const uint8_t*) in);
2213 default:
2214 return 0;
2215 }
2216}
2217
2218static cgltf_float cgltf_component_read_float(const void* in, cgltf_component_type component_type, cgltf_bool normalized)
2219{
2220 if (component_type == cgltf_component_type_r_32f)
2221 {
2222 return *((const float*) in);
2223 }
2224
2225 if (normalized)
2226 {
2227 switch (component_type)
2228 {
2229 // note: glTF spec doesn't currently define normalized conversions for 32-bit integers
2230 case cgltf_component_type_r_16:
2231 return *((const int16_t*) in) / (cgltf_float)32767;
2232 case cgltf_component_type_r_16u:
2233 return *((const uint16_t*) in) / (cgltf_float)65535;
2234 case cgltf_component_type_r_8:
2235 return *((const int8_t*) in) / (cgltf_float)127;
2236 case cgltf_component_type_r_8u:
2237 return *((const uint8_t*) in) / (cgltf_float)255;
2238 default:
2239 return 0;
2240 }
2241 }
2242
2243 return (cgltf_float)cgltf_component_read_integer(in, component_type);
2244}
2245
2246static cgltf_bool cgltf_element_read_float(const uint8_t* element, cgltf_type type, cgltf_component_type component_type, cgltf_bool normalized, cgltf_float* out, cgltf_size element_size)
2247{
2248 cgltf_size num_components = cgltf_num_components(type);
2249
2250 if (element_size < num_components) {
2251 return 0;
2252 }
2253
2254 // There are three special cases for component extraction, see #data-alignment in the 2.0 spec.
2255
2256 cgltf_size component_size = cgltf_component_size(component_type);
2257
2258 if (type == cgltf_type_mat2 && component_size == 1)
2259 {
2260 out[0] = cgltf_component_read_float(element, component_type, normalized);
2261 out[1] = cgltf_component_read_float(element + 1, component_type, normalized);
2262 out[2] = cgltf_component_read_float(element + 4, component_type, normalized);
2263 out[3] = cgltf_component_read_float(element + 5, component_type, normalized);
2264 return 1;
2265 }
2266
2267 if (type == cgltf_type_mat3 && component_size == 1)
2268 {
2269 out[0] = cgltf_component_read_float(element, component_type, normalized);
2270 out[1] = cgltf_component_read_float(element + 1, component_type, normalized);
2271 out[2] = cgltf_component_read_float(element + 2, component_type, normalized);
2272 out[3] = cgltf_component_read_float(element + 4, component_type, normalized);
2273 out[4] = cgltf_component_read_float(element + 5, component_type, normalized);
2274 out[5] = cgltf_component_read_float(element + 6, component_type, normalized);
2275 out[6] = cgltf_component_read_float(element + 8, component_type, normalized);
2276 out[7] = cgltf_component_read_float(element + 9, component_type, normalized);
2277 out[8] = cgltf_component_read_float(element + 10, component_type, normalized);
2278 return 1;
2279 }
2280
2281 if (type == cgltf_type_mat3 && component_size == 2)
2282 {
2283 out[0] = cgltf_component_read_float(element, component_type, normalized);
2284 out[1] = cgltf_component_read_float(element + 2, component_type, normalized);
2285 out[2] = cgltf_component_read_float(element + 4, component_type, normalized);
2286 out[3] = cgltf_component_read_float(element + 8, component_type, normalized);
2287 out[4] = cgltf_component_read_float(element + 10, component_type, normalized);
2288 out[5] = cgltf_component_read_float(element + 12, component_type, normalized);
2289 out[6] = cgltf_component_read_float(element + 16, component_type, normalized);
2290 out[7] = cgltf_component_read_float(element + 18, component_type, normalized);
2291 out[8] = cgltf_component_read_float(element + 20, component_type, normalized);
2292 return 1;
2293 }
2294
2295 for (cgltf_size i = 0; i < num_components; ++i)
2296 {
2297 out[i] = cgltf_component_read_float(element + component_size * i, component_type, normalized);
2298 }
2299 return 1;
2300}
2301
2302const uint8_t* cgltf_buffer_view_data(const cgltf_buffer_view* view)
2303{
2304 if (view->data)
2305 return (const uint8_t*)view->data;
2306
2307 if (!view->buffer->data)
2308 return NULL;
2309
2310 const uint8_t* result = (const uint8_t*)view->buffer->data;
2311 result += view->offset;
2312 return result;
2313}
2314
2315cgltf_bool cgltf_accessor_read_float(const cgltf_accessor* accessor, cgltf_size index, cgltf_float* out, cgltf_size element_size)
2316{
2317 if (accessor->is_sparse)
2318 {
2319 return 0;
2320 }
2321 if (accessor->buffer_view == NULL)
2322 {
2323 memset(out, 0, element_size * sizeof(cgltf_float));
2324 return 1;
2325 }
2326 const uint8_t* element = cgltf_buffer_view_data(accessor->buffer_view);
2327 if (element == NULL)
2328 {
2329 return 0;
2330 }
2331 element += accessor->offset + accessor->stride * index;
2332 return cgltf_element_read_float(element, accessor->type, accessor->component_type, accessor->normalized, out, element_size);
2333}
2334
2335cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_float* out, cgltf_size float_count)
2336{
2337 cgltf_size floats_per_element = cgltf_num_components(accessor->type);
2338 cgltf_size available_floats = accessor->count * floats_per_element;
2339 if (out == NULL)
2340 {
2341 return available_floats;
2342 }
2343
2344 float_count = available_floats < float_count ? available_floats : float_count;
2345 cgltf_size element_count = float_count / floats_per_element;
2346
2347 // First pass: convert each element in the base accessor.
2348 if (accessor->buffer_view == NULL)
2349 {
2350 memset(out, 0, element_count * floats_per_element * sizeof(cgltf_float));
2351 }
2352 else
2353 {
2354 const uint8_t* element = cgltf_buffer_view_data(accessor->buffer_view);
2355 if (element == NULL)
2356 {
2357 return 0;
2358 }
2359 element += accessor->offset;
2360
2361 if (accessor->component_type == cgltf_component_type_r_32f && accessor->stride == floats_per_element * sizeof(cgltf_float))
2362 {
2363 memcpy(out, element, element_count * floats_per_element * sizeof(cgltf_float));
2364 }
2365 else
2366 {
2367 cgltf_float* dest = out;
2368
2369 for (cgltf_size index = 0; index < element_count; index++, dest += floats_per_element, element += accessor->stride)
2370 {
2371 if (!cgltf_element_read_float(element, accessor->type, accessor->component_type, accessor->normalized, dest, floats_per_element))
2372 {
2373 return 0;
2374 }
2375 }
2376 }
2377 }
2378
2379 // Second pass: write out each element in the sparse accessor.
2380 if (accessor->is_sparse)
2381 {
2382 const cgltf_accessor_sparse* sparse = &accessor->sparse;
2383
2384 const uint8_t* index_data = cgltf_buffer_view_data(sparse->indices_buffer_view);
2385 const uint8_t* reader_head = cgltf_buffer_view_data(sparse->values_buffer_view);
2386
2387 if (index_data == NULL || reader_head == NULL)
2388 {
2389 return 0;
2390 }
2391
2392 index_data += sparse->indices_byte_offset;
2393 reader_head += sparse->values_byte_offset;
2394
2395 cgltf_size index_stride = cgltf_component_size(sparse->indices_component_type);
2396 for (cgltf_size reader_index = 0; reader_index < sparse->count; reader_index++, index_data += index_stride, reader_head += accessor->stride)
2397 {
2398 size_t writer_index = cgltf_component_read_index(index_data, sparse->indices_component_type);
2399 float* writer_head = out + writer_index * floats_per_element;
2400
2401 if (!cgltf_element_read_float(reader_head, accessor->type, accessor->component_type, accessor->normalized, writer_head, floats_per_element))
2402 {
2403 return 0;
2404 }
2405 }
2406 }
2407
2408 return element_count * floats_per_element;
2409}
2410
2411static cgltf_uint cgltf_component_read_uint(const void* in, cgltf_component_type component_type)
2412{
2413 switch (component_type)
2414 {
2415 case cgltf_component_type_r_8:
2416 return *((const int8_t*) in);
2417
2418 case cgltf_component_type_r_8u:
2419 return *((const uint8_t*) in);
2420
2421 case cgltf_component_type_r_16:
2422 return *((const int16_t*) in);
2423
2424 case cgltf_component_type_r_16u:
2425 return *((const uint16_t*) in);
2426
2427 case cgltf_component_type_r_32u:
2428 return *((const uint32_t*) in);
2429
2430 default:
2431 return 0;
2432 }
2433}
2434
2435static cgltf_bool cgltf_element_read_uint(const uint8_t* element, cgltf_type type, cgltf_component_type component_type, cgltf_uint* out, cgltf_size element_size)
2436{
2437 cgltf_size num_components = cgltf_num_components(type);
2438
2439 if (element_size < num_components)
2440 {
2441 return 0;
2442 }
2443
2444 // Reading integer matrices is not a valid use case
2445 if (type == cgltf_type_mat2 || type == cgltf_type_mat3 || type == cgltf_type_mat4)
2446 {
2447 return 0;
2448 }
2449
2450 cgltf_size component_size = cgltf_component_size(component_type);
2451
2452 for (cgltf_size i = 0; i < num_components; ++i)
2453 {
2454 out[i] = cgltf_component_read_uint(element + component_size * i, component_type);
2455 }
2456 return 1;
2457}
2458
2459cgltf_bool cgltf_accessor_read_uint(const cgltf_accessor* accessor, cgltf_size index, cgltf_uint* out, cgltf_size element_size)
2460{
2461 if (accessor->is_sparse)
2462 {
2463 return 0;
2464 }
2465 if (accessor->buffer_view == NULL)
2466 {
2467 memset(out, 0, element_size * sizeof( cgltf_uint ));
2468 return 1;
2469 }
2470 const uint8_t* element = cgltf_buffer_view_data(accessor->buffer_view);
2471 if (element == NULL)
2472 {
2473 return 0;
2474 }
2475 element += accessor->offset + accessor->stride * index;
2476 return cgltf_element_read_uint(element, accessor->type, accessor->component_type, out, element_size);
2477}
2478
2479cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size index)
2480{
2481 if (accessor->is_sparse)
2482 {
2483 return 0; // This is an error case, but we can't communicate the error with existing interface.
2484 }
2485 if (accessor->buffer_view == NULL)
2486 {
2487 return 0;
2488 }
2489 const uint8_t* element = cgltf_buffer_view_data(accessor->buffer_view);
2490 if (element == NULL)
2491 {
2492 return 0; // This is an error case, but we can't communicate the error with existing interface.
2493 }
2494 element += accessor->offset + accessor->stride * index;
2495 return cgltf_component_read_index(element, accessor->component_type);
2496}
2497
2498cgltf_size cgltf_mesh_index(const cgltf_data* data, const cgltf_mesh* object)
2499{
2500 assert(object && (cgltf_size)(object - data->meshes) < data->meshes_count);
2501 return (cgltf_size)(object - data->meshes);
2502}
2503
2504cgltf_size cgltf_material_index(const cgltf_data* data, const cgltf_material* object)
2505{
2506 assert(object && (cgltf_size)(object - data->materials) < data->materials_count);
2507 return (cgltf_size)(object - data->materials);
2508}
2509
2510cgltf_size cgltf_accessor_index(const cgltf_data* data, const cgltf_accessor* object)
2511{
2512 assert(object && (cgltf_size)(object - data->accessors) < data->accessors_count);
2513 return (cgltf_size)(object - data->accessors);
2514}
2515
2516cgltf_size cgltf_buffer_view_index(const cgltf_data* data, const cgltf_buffer_view* object)
2517{
2518 assert(object && (cgltf_size)(object - data->buffer_views) < data->buffer_views_count);
2519 return (cgltf_size)(object - data->buffer_views);
2520}
2521
2522cgltf_size cgltf_buffer_index(const cgltf_data* data, const cgltf_buffer* object)
2523{
2524 assert(object && (cgltf_size)(object - data->buffers) < data->buffers_count);
2525 return (cgltf_size)(object - data->buffers);
2526}
2527
2528cgltf_size cgltf_image_index(const cgltf_data* data, const cgltf_image* object)
2529{
2530 assert(object && (cgltf_size)(object - data->images) < data->images_count);
2531 return (cgltf_size)(object - data->images);
2532}
2533
2534cgltf_size cgltf_texture_index(const cgltf_data* data, const cgltf_texture* object)
2535{
2536 assert(object && (cgltf_size)(object - data->textures) < data->textures_count);
2537 return (cgltf_size)(object - data->textures);
2538}
2539
2540cgltf_size cgltf_sampler_index(const cgltf_data* data, const cgltf_sampler* object)
2541{
2542 assert(object && (cgltf_size)(object - data->samplers) < data->samplers_count);
2543 return (cgltf_size)(object - data->samplers);
2544}
2545
2546cgltf_size cgltf_skin_index(const cgltf_data* data, const cgltf_skin* object)
2547{
2548 assert(object && (cgltf_size)(object - data->skins) < data->skins_count);
2549 return (cgltf_size)(object - data->skins);
2550}
2551
2552cgltf_size cgltf_camera_index(const cgltf_data* data, const cgltf_camera* object)
2553{
2554 assert(object && (cgltf_size)(object - data->cameras) < data->cameras_count);
2555 return (cgltf_size)(object - data->cameras);
2556}
2557
2558cgltf_size cgltf_light_index(const cgltf_data* data, const cgltf_light* object)
2559{
2560 assert(object && (cgltf_size)(object - data->lights) < data->lights_count);
2561 return (cgltf_size)(object - data->lights);
2562}
2563
2564cgltf_size cgltf_node_index(const cgltf_data* data, const cgltf_node* object)
2565{
2566 assert(object && (cgltf_size)(object - data->nodes) < data->nodes_count);
2567 return (cgltf_size)(object - data->nodes);
2568}
2569
2570cgltf_size cgltf_scene_index(const cgltf_data* data, const cgltf_scene* object)
2571{
2572 assert(object && (cgltf_size)(object - data->scenes) < data->scenes_count);
2573 return (cgltf_size)(object - data->scenes);
2574}
2575
2576cgltf_size cgltf_animation_index(const cgltf_data* data, const cgltf_animation* object)
2577{
2578 assert(object && (cgltf_size)(object - data->animations) < data->animations_count);
2579 return (cgltf_size)(object - data->animations);
2580}
2581
2582cgltf_size cgltf_animation_sampler_index(const cgltf_animation* animation, const cgltf_animation_sampler* object)
2583{
2584 assert(object && (cgltf_size)(object - animation->samplers) < animation->samplers_count);
2585 return (cgltf_size)(object - animation->samplers);
2586}
2587
2588cgltf_size cgltf_animation_channel_index(const cgltf_animation* animation, const cgltf_animation_channel* object)
2589{
2590 assert(object && (cgltf_size)(object - animation->channels) < animation->channels_count);
2591 return (cgltf_size)(object - animation->channels);
2592}
2593
2594cgltf_size cgltf_accessor_unpack_indices(const cgltf_accessor* accessor, void* out, cgltf_size out_component_size, cgltf_size index_count)
2595{
2596 if (out == NULL)
2597 {
2598 return accessor->count;
2599 }
2600
2601 index_count = accessor->count < index_count ? accessor->count : index_count;
2602 cgltf_size index_component_size = cgltf_component_size(accessor->component_type);
2603
2604 if (accessor->is_sparse)
2605 {
2606 return 0;
2607 }
2608 if (accessor->buffer_view == NULL)
2609 {
2610 return 0;
2611 }
2612 if (index_component_size > out_component_size)
2613 {
2614 return 0;
2615 }
2616 const uint8_t* element = cgltf_buffer_view_data(accessor->buffer_view);
2617 if (element == NULL)
2618 {
2619 return 0;
2620 }
2621 element += accessor->offset;
2622
2623 if (index_component_size == out_component_size && accessor->stride == out_component_size)
2624 {
2625 memcpy(out, element, index_count * index_component_size);
2626 return index_count;
2627 }
2628
2629 // The component size of the output array is larger than the component size of the index data, so index data will be padded.
2630 switch (out_component_size)
2631 {
2632 case 2:
2633 for (cgltf_size index = 0; index < index_count; index++, element += accessor->stride)
2634 {
2635 ((uint16_t*)out)[index] = (uint16_t)cgltf_component_read_index(element, accessor->component_type);
2636 }
2637 break;
2638 case 4:
2639 for (cgltf_size index = 0; index < index_count; index++, element += accessor->stride)
2640 {
2641 ((uint32_t*)out)[index] = (uint32_t)cgltf_component_read_index(element, accessor->component_type);
2642 }
2643 break;
2644 default:
2645 break;
2646 }
2647
2648 return index_count;
2649}
2650
2651#define CGLTF_ERROR_JSON -1
2652#define CGLTF_ERROR_NOMEM -2
2653#define CGLTF_ERROR_LEGACY -3
2654
2655#define CGLTF_CHECK_TOKTYPE(tok_, type_) if ((tok_).type != (type_)) { return CGLTF_ERROR_JSON; }
2656#define CGLTF_CHECK_TOKTYPE_RET(tok_, type_, ret_) if ((tok_).type != (type_)) { return ret_; }
2657#define CGLTF_CHECK_KEY(tok_) if ((tok_).type != JSMN_STRING || (tok_).size == 0) { return CGLTF_ERROR_JSON; } /* checking size for 0 verifies that a value follows the key */
2658
2659#define CGLTF_PTRINDEX(type, idx) (type*)((cgltf_size)idx + 1)
2660#define CGLTF_PTRFIXUP(var, data, size) if (var) { if ((cgltf_size)var > size) { return CGLTF_ERROR_JSON; } var = &data[(cgltf_size)var-1]; }
2661#define CGLTF_PTRFIXUP_REQ(var, data, size) if (!var || (cgltf_size)var > size) { return CGLTF_ERROR_JSON; } var = &data[(cgltf_size)var-1];
2662
2663static int cgltf_json_strcmp(jsmntok_t const* tok, const uint8_t* json_chunk, const char* str)
2664{
2665 CGLTF_CHECK_TOKTYPE(*tok, JSMN_STRING);
2666 size_t const str_len = strlen(str);
2667 size_t const name_length = (size_t)(tok->end - tok->start);
2668 return (str_len == name_length) ? strncmp((const char*)json_chunk + tok->start, str, str_len) : 128;
2669}
2670
2671static int cgltf_json_to_int(jsmntok_t const* tok, const uint8_t* json_chunk)
2672{
2673 CGLTF_CHECK_TOKTYPE(*tok, JSMN_PRIMITIVE);
2674 char tmp[128];
2675 int size = (size_t)(tok->end - tok->start) < sizeof(tmp) ? (int)(tok->end - tok->start) : (int)(sizeof(tmp) - 1);
2676 strncpy(tmp, (const char*)json_chunk + tok->start, size);
2677 tmp[size] = 0;
2678 return CGLTF_ATOI(tmp);
2679}
2680
2681static cgltf_size cgltf_json_to_size(jsmntok_t const* tok, const uint8_t* json_chunk)
2682{
2683 CGLTF_CHECK_TOKTYPE_RET(*tok, JSMN_PRIMITIVE, 0);
2684 char tmp[128];
2685 int size = (size_t)(tok->end - tok->start) < sizeof(tmp) ? (int)(tok->end - tok->start) : (int)(sizeof(tmp) - 1);
2686 strncpy(tmp, (const char*)json_chunk + tok->start, size);
2687 tmp[size] = 0;
2688 long long res = CGLTF_ATOLL(tmp);
2689 return res < 0 ? 0 : (cgltf_size)res;
2690}
2691
2692static cgltf_float cgltf_json_to_float(jsmntok_t const* tok, const uint8_t* json_chunk)
2693{
2694 CGLTF_CHECK_TOKTYPE(*tok, JSMN_PRIMITIVE);
2695 char tmp[128];
2696 int size = (size_t)(tok->end - tok->start) < sizeof(tmp) ? (int)(tok->end - tok->start) : (int)(sizeof(tmp) - 1);
2697 strncpy(tmp, (const char*)json_chunk + tok->start, size);
2698 tmp[size] = 0;
2699 return (cgltf_float)CGLTF_ATOF(tmp);
2700}
2701
2702static cgltf_bool cgltf_json_to_bool(jsmntok_t const* tok, const uint8_t* json_chunk)
2703{
2704 int size = (int)(tok->end - tok->start);
2705 return size == 4 && memcmp(json_chunk + tok->start, "true", 4) == 0;
2706}
2707
2708static int cgltf_skip_json(jsmntok_t const* tokens, int i)
2709{
2710 int end = i + 1;
2711
2712 while (i < end)
2713 {
2714 switch (tokens[i].type)
2715 {
2716 case JSMN_OBJECT:
2717 end += tokens[i].size * 2;
2718 break;
2719
2720 case JSMN_ARRAY:
2721 end += tokens[i].size;
2722 break;
2723
2724 case JSMN_PRIMITIVE:
2725 case JSMN_STRING:
2726 break;
2727
2728 default:
2729 return -1;
2730 }
2731
2732 i++;
2733 }
2734
2735 return i;
2736}
2737
2738static void cgltf_fill_float_array(float* out_array, int size, float value)
2739{
2740 for (int j = 0; j < size; ++j)
2741 {
2742 out_array[j] = value;
2743 }
2744}
2745
2746static int cgltf_parse_json_float_array(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, float* out_array, int size)
2747{
2748 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_ARRAY);
2749 if (tokens[i].size != size)
2750 {
2751 return CGLTF_ERROR_JSON;
2752 }
2753 ++i;
2754 for (int j = 0; j < size; ++j)
2755 {
2756 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE);
2757 out_array[j] = cgltf_json_to_float(tokens + i, json_chunk);
2758 ++i;
2759 }
2760 return i;
2761}
2762
2763static int cgltf_parse_json_string(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, char** out_string)
2764{
2765 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_STRING);
2766 if (*out_string)
2767 {
2768 return CGLTF_ERROR_JSON;
2769 }
2770 int size = (int)(tokens[i].end - tokens[i].start);
2771 char* result = (char*)options->memory.alloc_func(options->memory.user_data, size + 1);
2772 if (!result)
2773 {
2774 return CGLTF_ERROR_NOMEM;
2775 }
2776 strncpy(result, (const char*)json_chunk + tokens[i].start, size);
2777 result[size] = 0;
2778 *out_string = result;
2779 return i + 1;
2780}
2781
2782static int cgltf_parse_json_array(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, size_t element_size, void** out_array, cgltf_size* out_size)
2783{
2784 (void)json_chunk;
2785 if (tokens[i].type != JSMN_ARRAY)
2786 {
2787 return tokens[i].type == JSMN_OBJECT ? CGLTF_ERROR_LEGACY : CGLTF_ERROR_JSON;
2788 }
2789 if (*out_array)
2790 {
2791 return CGLTF_ERROR_JSON;
2792 }
2793 int size = tokens[i].size;
2794 void* result = cgltf_calloc(options, element_size, size);
2795 if (!result)
2796 {
2797 return CGLTF_ERROR_NOMEM;
2798 }
2799 *out_array = result;
2800 *out_size = size;
2801 return i + 1;
2802}
2803
2804static int cgltf_parse_json_string_array(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, char*** out_array, cgltf_size* out_size)
2805{
2806 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_ARRAY);
2807 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(char*), (void**)out_array, out_size);
2808 if (i < 0)
2809 {
2810 return i;
2811 }
2812
2813 for (cgltf_size j = 0; j < *out_size; ++j)
2814 {
2815 i = cgltf_parse_json_string(options, tokens, i, json_chunk, j + (*out_array));
2816 if (i < 0)
2817 {
2818 return i;
2819 }
2820 }
2821 return i;
2822}
2823
2824static void cgltf_parse_attribute_type(const char* name, cgltf_attribute_type* out_type, int* out_index)
2825{
2826 if (*name == '_')
2827 {
2828 *out_type = cgltf_attribute_type_custom;
2829 return;
2830 }
2831
2832 const char* us = strchr(name, '_');
2833 size_t len = us ? (size_t)(us - name) : strlen(name);
2834
2835 if (len == 8 && strncmp(name, "POSITION", 8) == 0)
2836 {
2837 *out_type = cgltf_attribute_type_position;
2838 }
2839 else if (len == 6 && strncmp(name, "NORMAL", 6) == 0)
2840 {
2841 *out_type = cgltf_attribute_type_normal;
2842 }
2843 else if (len == 7 && strncmp(name, "TANGENT", 7) == 0)
2844 {
2845 *out_type = cgltf_attribute_type_tangent;
2846 }
2847 else if (len == 8 && strncmp(name, "TEXCOORD", 8) == 0)
2848 {
2849 *out_type = cgltf_attribute_type_texcoord;
2850 }
2851 else if (len == 5 && strncmp(name, "COLOR", 5) == 0)
2852 {
2853 *out_type = cgltf_attribute_type_color;
2854 }
2855 else if (len == 6 && strncmp(name, "JOINTS", 6) == 0)
2856 {
2857 *out_type = cgltf_attribute_type_joints;
2858 }
2859 else if (len == 7 && strncmp(name, "WEIGHTS", 7) == 0)
2860 {
2861 *out_type = cgltf_attribute_type_weights;
2862 }
2863 else
2864 {
2865 *out_type = cgltf_attribute_type_invalid;
2866 }
2867
2868 if (us && *out_type != cgltf_attribute_type_invalid)
2869 {
2870 *out_index = CGLTF_ATOI(us + 1);
2871 if (*out_index < 0)
2872 {
2873 *out_type = cgltf_attribute_type_invalid;
2874 *out_index = 0;
2875 }
2876 }
2877}
2878
2879static int cgltf_parse_json_attribute_list(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_attribute** out_attributes, cgltf_size* out_attributes_count)
2880{
2881 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
2882
2883 if (*out_attributes)
2884 {
2885 return CGLTF_ERROR_JSON;
2886 }
2887
2888 *out_attributes_count = tokens[i].size;
2889 *out_attributes = (cgltf_attribute*)cgltf_calloc(options, sizeof(cgltf_attribute), *out_attributes_count);
2890 ++i;
2891
2892 if (!*out_attributes)
2893 {
2894 return CGLTF_ERROR_NOMEM;
2895 }
2896
2897 for (cgltf_size j = 0; j < *out_attributes_count; ++j)
2898 {
2899 CGLTF_CHECK_KEY(tokens[i]);
2900
2901 i = cgltf_parse_json_string(options, tokens, i, json_chunk, &(*out_attributes)[j].name);
2902 if (i < 0)
2903 {
2904 return CGLTF_ERROR_JSON;
2905 }
2906
2907 cgltf_parse_attribute_type((*out_attributes)[j].name, &(*out_attributes)[j].type, &(*out_attributes)[j].index);
2908
2909 (*out_attributes)[j].data = CGLTF_PTRINDEX(cgltf_accessor, cgltf_json_to_int(tokens + i, json_chunk));
2910 ++i;
2911 }
2912
2913 return i;
2914}
2915
2916static int cgltf_parse_json_extras(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_extras* out_extras)
2917{
2918 if (out_extras->data)
2919 {
2920 return CGLTF_ERROR_JSON;
2921 }
2922
2923 /* fill deprecated fields for now, this will be removed in the future */
2924 out_extras->start_offset = tokens[i].start;
2925 out_extras->end_offset = tokens[i].end;
2926
2927 size_t start = tokens[i].start;
2928 size_t size = tokens[i].end - start;
2929 out_extras->data = (char*)options->memory.alloc_func(options->memory.user_data, size + 1);
2930 if (!out_extras->data)
2931 {
2932 return CGLTF_ERROR_NOMEM;
2933 }
2934 strncpy(out_extras->data, (const char*)json_chunk + start, size);
2935 out_extras->data[size] = '\0';
2936
2937 i = cgltf_skip_json(tokens, i);
2938 return i;
2939}
2940
2941static int cgltf_parse_json_unprocessed_extension(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_extension* out_extension)
2942{
2943 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_STRING);
2944 CGLTF_CHECK_TOKTYPE(tokens[i+1], JSMN_OBJECT);
2945 if (out_extension->name)
2946 {
2947 return CGLTF_ERROR_JSON;
2948 }
2949
2950 cgltf_size name_length = tokens[i].end - tokens[i].start;
2951 out_extension->name = (char*)options->memory.alloc_func(options->memory.user_data, name_length + 1);
2952 if (!out_extension->name)
2953 {
2954 return CGLTF_ERROR_NOMEM;
2955 }
2956 strncpy(out_extension->name, (const char*)json_chunk + tokens[i].start, name_length);
2957 out_extension->name[name_length] = 0;
2958 i++;
2959
2960 size_t start = tokens[i].start;
2961 size_t size = tokens[i].end - start;
2962 out_extension->data = (char*)options->memory.alloc_func(options->memory.user_data, size + 1);
2963 if (!out_extension->data)
2964 {
2965 return CGLTF_ERROR_NOMEM;
2966 }
2967 strncpy(out_extension->data, (const char*)json_chunk + start, size);
2968 out_extension->data[size] = '\0';
2969
2970 i = cgltf_skip_json(tokens, i);
2971
2972 return i;
2973}
2974
2975static int cgltf_parse_json_unprocessed_extensions(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_size* out_extensions_count, cgltf_extension** out_extensions)
2976{
2977 ++i;
2978
2979 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
2980 if(*out_extensions)
2981 {
2982 return CGLTF_ERROR_JSON;
2983 }
2984
2985 int extensions_size = tokens[i].size;
2986 *out_extensions_count = 0;
2987 *out_extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size);
2988
2989 if (!*out_extensions)
2990 {
2991 return CGLTF_ERROR_NOMEM;
2992 }
2993
2994 ++i;
2995
2996 for (int j = 0; j < extensions_size; ++j)
2997 {
2998 CGLTF_CHECK_KEY(tokens[i]);
2999
3000 cgltf_size extension_index = (*out_extensions_count)++;
3001 cgltf_extension* extension = &((*out_extensions)[extension_index]);
3002 i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, extension);
3003
3004 if (i < 0)
3005 {
3006 return i;
3007 }
3008 }
3009 return i;
3010}
3011
3012static int cgltf_parse_json_draco_mesh_compression(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_draco_mesh_compression* out_draco_mesh_compression)
3013{
3014 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3015
3016 int size = tokens[i].size;
3017 ++i;
3018
3019 for (int j = 0; j < size; ++j)
3020 {
3021 CGLTF_CHECK_KEY(tokens[i]);
3022
3023 if (cgltf_json_strcmp(tokens + i, json_chunk, "attributes") == 0)
3024 {
3025 i = cgltf_parse_json_attribute_list(options, tokens, i + 1, json_chunk, &out_draco_mesh_compression->attributes, &out_draco_mesh_compression->attributes_count);
3026 }
3027 else if (cgltf_json_strcmp(tokens + i, json_chunk, "bufferView") == 0)
3028 {
3029 ++i;
3030 out_draco_mesh_compression->buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk));
3031 ++i;
3032 }
3033 else
3034 {
3035 i = cgltf_skip_json(tokens, i+1);
3036 }
3037
3038 if (i < 0)
3039 {
3040 return i;
3041 }
3042 }
3043
3044 return i;
3045}
3046
3047static int cgltf_parse_json_mesh_gpu_instancing(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_mesh_gpu_instancing* out_mesh_gpu_instancing)
3048{
3049 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3050
3051 int size = tokens[i].size;
3052 ++i;
3053
3054 for (int j = 0; j < size; ++j)
3055 {
3056 CGLTF_CHECK_KEY(tokens[i]);
3057
3058 if (cgltf_json_strcmp(tokens + i, json_chunk, "attributes") == 0)
3059 {
3060 i = cgltf_parse_json_attribute_list(options, tokens, i + 1, json_chunk, &out_mesh_gpu_instancing->attributes, &out_mesh_gpu_instancing->attributes_count);
3061 }
3062 else
3063 {
3064 i = cgltf_skip_json(tokens, i+1);
3065 }
3066
3067 if (i < 0)
3068 {
3069 return i;
3070 }
3071 }
3072
3073 return i;
3074}
3075
3076static int cgltf_parse_json_material_mapping_data(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_material_mapping* out_mappings, cgltf_size* offset)
3077{
3078 (void)options;
3079 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_ARRAY);
3080
3081 int size = tokens[i].size;
3082 ++i;
3083
3084 for (int j = 0; j < size; ++j)
3085 {
3086 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3087
3088 int obj_size = tokens[i].size;
3089 ++i;
3090
3091 int material = -1;
3092 int variants_tok = -1;
3093 int extras_tok = -1;
3094
3095 for (int k = 0; k < obj_size; ++k)
3096 {
3097 CGLTF_CHECK_KEY(tokens[i]);
3098
3099 if (cgltf_json_strcmp(tokens + i, json_chunk, "material") == 0)
3100 {
3101 ++i;
3102 material = cgltf_json_to_int(tokens + i, json_chunk);
3103 ++i;
3104 }
3105 else if (cgltf_json_strcmp(tokens + i, json_chunk, "variants") == 0)
3106 {
3107 variants_tok = i+1;
3108 CGLTF_CHECK_TOKTYPE(tokens[variants_tok], JSMN_ARRAY);
3109
3110 i = cgltf_skip_json(tokens, i+1);
3111 }
3112 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
3113 {
3114 extras_tok = i + 1;
3115 i = cgltf_skip_json(tokens, extras_tok);
3116 }
3117 else
3118 {
3119 i = cgltf_skip_json(tokens, i+1);
3120 }
3121
3122 if (i < 0)
3123 {
3124 return i;
3125 }
3126 }
3127
3128 if (material < 0 || variants_tok < 0)
3129 {
3130 return CGLTF_ERROR_JSON;
3131 }
3132
3133 if (out_mappings)
3134 {
3135 for (int k = 0; k < tokens[variants_tok].size; ++k)
3136 {
3137 int variant = cgltf_json_to_int(&tokens[variants_tok + 1 + k], json_chunk);
3138 if (variant < 0)
3139 return variant;
3140
3141 out_mappings[*offset].material = CGLTF_PTRINDEX(cgltf_material, material);
3142 out_mappings[*offset].variant = variant;
3143
3144 if (extras_tok >= 0)
3145 {
3146 int e = cgltf_parse_json_extras(options, tokens, extras_tok, json_chunk, &out_mappings[*offset].extras);
3147 if (e < 0)
3148 return e;
3149 }
3150
3151 (*offset)++;
3152 }
3153 }
3154 else
3155 {
3156 (*offset) += tokens[variants_tok].size;
3157 }
3158 }
3159
3160 return i;
3161}
3162
3163static int cgltf_parse_json_material_mappings(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_primitive* out_prim)
3164{
3165 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3166
3167 int size = tokens[i].size;
3168 ++i;
3169
3170 for (int j = 0; j < size; ++j)
3171 {
3172 CGLTF_CHECK_KEY(tokens[i]);
3173
3174 if (cgltf_json_strcmp(tokens + i, json_chunk, "mappings") == 0)
3175 {
3176 if (out_prim->mappings)
3177 {
3178 return CGLTF_ERROR_JSON;
3179 }
3180
3181 cgltf_size mappings_offset = 0;
3182 int k = cgltf_parse_json_material_mapping_data(options, tokens, i + 1, json_chunk, NULL, &mappings_offset);
3183 if (k < 0)
3184 {
3185 return k;
3186 }
3187
3188 out_prim->mappings_count = mappings_offset;
3189 out_prim->mappings = (cgltf_material_mapping*)cgltf_calloc(options, sizeof(cgltf_material_mapping), out_prim->mappings_count);
3190
3191 mappings_offset = 0;
3192 i = cgltf_parse_json_material_mapping_data(options, tokens, i + 1, json_chunk, out_prim->mappings, &mappings_offset);
3193 }
3194 else
3195 {
3196 i = cgltf_skip_json(tokens, i+1);
3197 }
3198
3199 if (i < 0)
3200 {
3201 return i;
3202 }
3203 }
3204
3205 return i;
3206}
3207
3208static cgltf_primitive_type cgltf_json_to_primitive_type(jsmntok_t const* tok, const uint8_t* json_chunk)
3209{
3210 int type = cgltf_json_to_int(tok, json_chunk);
3211
3212 switch (type)
3213 {
3214 case 0:
3215 return cgltf_primitive_type_points;
3216 case 1:
3217 return cgltf_primitive_type_lines;
3218 case 2:
3219 return cgltf_primitive_type_line_loop;
3220 case 3:
3221 return cgltf_primitive_type_line_strip;
3222 case 4:
3223 return cgltf_primitive_type_triangles;
3224 case 5:
3225 return cgltf_primitive_type_triangle_strip;
3226 case 6:
3227 return cgltf_primitive_type_triangle_fan;
3228 default:
3229 return cgltf_primitive_type_invalid;
3230 }
3231}
3232
3233static int cgltf_parse_json_primitive(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_primitive* out_prim)
3234{
3235 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3236
3237 out_prim->type = cgltf_primitive_type_triangles;
3238
3239 int size = tokens[i].size;
3240 ++i;
3241
3242 for (int j = 0; j < size; ++j)
3243 {
3244 CGLTF_CHECK_KEY(tokens[i]);
3245
3246 if (cgltf_json_strcmp(tokens+i, json_chunk, "mode") == 0)
3247 {
3248 ++i;
3249 out_prim->type = cgltf_json_to_primitive_type(tokens+i, json_chunk);
3250 ++i;
3251 }
3252 else if (cgltf_json_strcmp(tokens+i, json_chunk, "indices") == 0)
3253 {
3254 ++i;
3255 out_prim->indices = CGLTF_PTRINDEX(cgltf_accessor, cgltf_json_to_int(tokens + i, json_chunk));
3256 ++i;
3257 }
3258 else if (cgltf_json_strcmp(tokens+i, json_chunk, "material") == 0)
3259 {
3260 ++i;
3261 out_prim->material = CGLTF_PTRINDEX(cgltf_material, cgltf_json_to_int(tokens + i, json_chunk));
3262 ++i;
3263 }
3264 else if (cgltf_json_strcmp(tokens+i, json_chunk, "attributes") == 0)
3265 {
3266 i = cgltf_parse_json_attribute_list(options, tokens, i + 1, json_chunk, &out_prim->attributes, &out_prim->attributes_count);
3267 }
3268 else if (cgltf_json_strcmp(tokens+i, json_chunk, "targets") == 0)
3269 {
3270 i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_morph_target), (void**)&out_prim->targets, &out_prim->targets_count);
3271 if (i < 0)
3272 {
3273 return i;
3274 }
3275
3276 for (cgltf_size k = 0; k < out_prim->targets_count; ++k)
3277 {
3278 i = cgltf_parse_json_attribute_list(options, tokens, i, json_chunk, &out_prim->targets[k].attributes, &out_prim->targets[k].attributes_count);
3279 if (i < 0)
3280 {
3281 return i;
3282 }
3283 }
3284 }
3285 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
3286 {
3287 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_prim->extras);
3288 }
3289 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
3290 {
3291 ++i;
3292
3293 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3294 if(out_prim->extensions)
3295 {
3296 return CGLTF_ERROR_JSON;
3297 }
3298
3299 int extensions_size = tokens[i].size;
3300 out_prim->extensions_count = 0;
3301 out_prim->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size);
3302
3303 if (!out_prim->extensions)
3304 {
3305 return CGLTF_ERROR_NOMEM;
3306 }
3307
3308 ++i;
3309 for (int k = 0; k < extensions_size; ++k)
3310 {
3311 CGLTF_CHECK_KEY(tokens[i]);
3312
3313 if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_draco_mesh_compression") == 0)
3314 {
3315 out_prim->has_draco_mesh_compression = 1;
3316 i = cgltf_parse_json_draco_mesh_compression(options, tokens, i + 1, json_chunk, &out_prim->draco_mesh_compression);
3317 }
3318 else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_variants") == 0)
3319 {
3320 i = cgltf_parse_json_material_mappings(options, tokens, i + 1, json_chunk, out_prim);
3321 }
3322 else
3323 {
3324 i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_prim->extensions[out_prim->extensions_count++]));
3325 }
3326
3327 if (i < 0)
3328 {
3329 return i;
3330 }
3331 }
3332 }
3333 else
3334 {
3335 i = cgltf_skip_json(tokens, i+1);
3336 }
3337
3338 if (i < 0)
3339 {
3340 return i;
3341 }
3342 }
3343
3344 return i;
3345}
3346
3347static int cgltf_parse_json_mesh(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_mesh* out_mesh)
3348{
3349 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3350
3351 int size = tokens[i].size;
3352 ++i;
3353
3354 for (int j = 0; j < size; ++j)
3355 {
3356 CGLTF_CHECK_KEY(tokens[i]);
3357
3358 if (cgltf_json_strcmp(tokens+i, json_chunk, "name") == 0)
3359 {
3360 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_mesh->name);
3361 }
3362 else if (cgltf_json_strcmp(tokens+i, json_chunk, "primitives") == 0)
3363 {
3364 i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_primitive), (void**)&out_mesh->primitives, &out_mesh->primitives_count);
3365 if (i < 0)
3366 {
3367 return i;
3368 }
3369
3370 for (cgltf_size prim_index = 0; prim_index < out_mesh->primitives_count; ++prim_index)
3371 {
3372 i = cgltf_parse_json_primitive(options, tokens, i, json_chunk, &out_mesh->primitives[prim_index]);
3373 if (i < 0)
3374 {
3375 return i;
3376 }
3377 }
3378 }
3379 else if (cgltf_json_strcmp(tokens + i, json_chunk, "weights") == 0)
3380 {
3381 i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_float), (void**)&out_mesh->weights, &out_mesh->weights_count);
3382 if (i < 0)
3383 {
3384 return i;
3385 }
3386
3387 i = cgltf_parse_json_float_array(tokens, i - 1, json_chunk, out_mesh->weights, (int)out_mesh->weights_count);
3388 }
3389 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
3390 {
3391 ++i;
3392
3393 out_mesh->extras.start_offset = tokens[i].start;
3394 out_mesh->extras.end_offset = tokens[i].end;
3395
3396 if (tokens[i].type == JSMN_OBJECT)
3397 {
3398 int extras_size = tokens[i].size;
3399 ++i;
3400
3401 for (int k = 0; k < extras_size; ++k)
3402 {
3403 CGLTF_CHECK_KEY(tokens[i]);
3404
3405 if (cgltf_json_strcmp(tokens+i, json_chunk, "targetNames") == 0 && tokens[i+1].type == JSMN_ARRAY)
3406 {
3407 i = cgltf_parse_json_string_array(options, tokens, i + 1, json_chunk, &out_mesh->target_names, &out_mesh->target_names_count);
3408 }
3409 else
3410 {
3411 i = cgltf_skip_json(tokens, i+1);
3412 }
3413
3414 if (i < 0)
3415 {
3416 return i;
3417 }
3418 }
3419 }
3420 else
3421 {
3422 i = cgltf_skip_json(tokens, i);
3423 }
3424 }
3425 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
3426 {
3427 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_mesh->extensions_count, &out_mesh->extensions);
3428 }
3429 else
3430 {
3431 i = cgltf_skip_json(tokens, i+1);
3432 }
3433
3434 if (i < 0)
3435 {
3436 return i;
3437 }
3438 }
3439
3440 return i;
3441}
3442
3443static int cgltf_parse_json_meshes(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
3444{
3445 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_mesh), (void**)&out_data->meshes, &out_data->meshes_count);
3446 if (i < 0)
3447 {
3448 return i;
3449 }
3450
3451 for (cgltf_size j = 0; j < out_data->meshes_count; ++j)
3452 {
3453 i = cgltf_parse_json_mesh(options, tokens, i, json_chunk, &out_data->meshes[j]);
3454 if (i < 0)
3455 {
3456 return i;
3457 }
3458 }
3459 return i;
3460}
3461
3462static cgltf_component_type cgltf_json_to_component_type(jsmntok_t const* tok, const uint8_t* json_chunk)
3463{
3464 int type = cgltf_json_to_int(tok, json_chunk);
3465
3466 switch (type)
3467 {
3468 case 5120:
3469 return cgltf_component_type_r_8;
3470 case 5121:
3471 return cgltf_component_type_r_8u;
3472 case 5122:
3473 return cgltf_component_type_r_16;
3474 case 5123:
3475 return cgltf_component_type_r_16u;
3476 case 5125:
3477 return cgltf_component_type_r_32u;
3478 case 5126:
3479 return cgltf_component_type_r_32f;
3480 default:
3481 return cgltf_component_type_invalid;
3482 }
3483}
3484
3485static int cgltf_parse_json_accessor_sparse(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_accessor_sparse* out_sparse)
3486{
3487 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3488
3489 int size = tokens[i].size;
3490 ++i;
3491
3492 for (int j = 0; j < size; ++j)
3493 {
3494 CGLTF_CHECK_KEY(tokens[i]);
3495
3496 if (cgltf_json_strcmp(tokens+i, json_chunk, "count") == 0)
3497 {
3498 ++i;
3499 out_sparse->count = cgltf_json_to_size(tokens + i, json_chunk);
3500 ++i;
3501 }
3502 else if (cgltf_json_strcmp(tokens+i, json_chunk, "indices") == 0)
3503 {
3504 ++i;
3505 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3506
3507 int indices_size = tokens[i].size;
3508 ++i;
3509
3510 for (int k = 0; k < indices_size; ++k)
3511 {
3512 CGLTF_CHECK_KEY(tokens[i]);
3513
3514 if (cgltf_json_strcmp(tokens+i, json_chunk, "bufferView") == 0)
3515 {
3516 ++i;
3517 out_sparse->indices_buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk));
3518 ++i;
3519 }
3520 else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteOffset") == 0)
3521 {
3522 ++i;
3523 out_sparse->indices_byte_offset = cgltf_json_to_size(tokens + i, json_chunk);
3524 ++i;
3525 }
3526 else if (cgltf_json_strcmp(tokens+i, json_chunk, "componentType") == 0)
3527 {
3528 ++i;
3529 out_sparse->indices_component_type = cgltf_json_to_component_type(tokens + i, json_chunk);
3530 ++i;
3531 }
3532 else
3533 {
3534 i = cgltf_skip_json(tokens, i+1);
3535 }
3536
3537 if (i < 0)
3538 {
3539 return i;
3540 }
3541 }
3542 }
3543 else if (cgltf_json_strcmp(tokens+i, json_chunk, "values") == 0)
3544 {
3545 ++i;
3546 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3547
3548 int values_size = tokens[i].size;
3549 ++i;
3550
3551 for (int k = 0; k < values_size; ++k)
3552 {
3553 CGLTF_CHECK_KEY(tokens[i]);
3554
3555 if (cgltf_json_strcmp(tokens+i, json_chunk, "bufferView") == 0)
3556 {
3557 ++i;
3558 out_sparse->values_buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk));
3559 ++i;
3560 }
3561 else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteOffset") == 0)
3562 {
3563 ++i;
3564 out_sparse->values_byte_offset = cgltf_json_to_size(tokens + i, json_chunk);
3565 ++i;
3566 }
3567 else
3568 {
3569 i = cgltf_skip_json(tokens, i+1);
3570 }
3571
3572 if (i < 0)
3573 {
3574 return i;
3575 }
3576 }
3577 }
3578 else
3579 {
3580 i = cgltf_skip_json(tokens, i+1);
3581 }
3582
3583 if (i < 0)
3584 {
3585 return i;
3586 }
3587 }
3588
3589 return i;
3590}
3591
3592static int cgltf_parse_json_accessor(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_accessor* out_accessor)
3593{
3594 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3595
3596 int size = tokens[i].size;
3597 ++i;
3598
3599 for (int j = 0; j < size; ++j)
3600 {
3601 CGLTF_CHECK_KEY(tokens[i]);
3602
3603 if (cgltf_json_strcmp(tokens + i, json_chunk, "name") == 0)
3604 {
3605 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_accessor->name);
3606 }
3607 else if (cgltf_json_strcmp(tokens+i, json_chunk, "bufferView") == 0)
3608 {
3609 ++i;
3610 out_accessor->buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk));
3611 ++i;
3612 }
3613 else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteOffset") == 0)
3614 {
3615 ++i;
3616 out_accessor->offset =
3617 cgltf_json_to_size(tokens+i, json_chunk);
3618 ++i;
3619 }
3620 else if (cgltf_json_strcmp(tokens+i, json_chunk, "componentType") == 0)
3621 {
3622 ++i;
3623 out_accessor->component_type = cgltf_json_to_component_type(tokens + i, json_chunk);
3624 ++i;
3625 }
3626 else if (cgltf_json_strcmp(tokens+i, json_chunk, "normalized") == 0)
3627 {
3628 ++i;
3629 out_accessor->normalized = cgltf_json_to_bool(tokens+i, json_chunk);
3630 ++i;
3631 }
3632 else if (cgltf_json_strcmp(tokens+i, json_chunk, "count") == 0)
3633 {
3634 ++i;
3635 out_accessor->count = cgltf_json_to_size(tokens+i, json_chunk);
3636 ++i;
3637 }
3638 else if (cgltf_json_strcmp(tokens+i, json_chunk, "type") == 0)
3639 {
3640 ++i;
3641 if (cgltf_json_strcmp(tokens+i, json_chunk, "SCALAR") == 0)
3642 {
3643 out_accessor->type = cgltf_type_scalar;
3644 }
3645 else if (cgltf_json_strcmp(tokens+i, json_chunk, "VEC2") == 0)
3646 {
3647 out_accessor->type = cgltf_type_vec2;
3648 }
3649 else if (cgltf_json_strcmp(tokens+i, json_chunk, "VEC3") == 0)
3650 {
3651 out_accessor->type = cgltf_type_vec3;
3652 }
3653 else if (cgltf_json_strcmp(tokens+i, json_chunk, "VEC4") == 0)
3654 {
3655 out_accessor->type = cgltf_type_vec4;
3656 }
3657 else if (cgltf_json_strcmp(tokens+i, json_chunk, "MAT2") == 0)
3658 {
3659 out_accessor->type = cgltf_type_mat2;
3660 }
3661 else if (cgltf_json_strcmp(tokens+i, json_chunk, "MAT3") == 0)
3662 {
3663 out_accessor->type = cgltf_type_mat3;
3664 }
3665 else if (cgltf_json_strcmp(tokens+i, json_chunk, "MAT4") == 0)
3666 {
3667 out_accessor->type = cgltf_type_mat4;
3668 }
3669 ++i;
3670 }
3671 else if (cgltf_json_strcmp(tokens + i, json_chunk, "min") == 0)
3672 {
3673 ++i;
3674 out_accessor->has_min = 1;
3675 // note: we can't parse the precise number of elements since type may not have been computed yet
3676 int min_size = tokens[i].size > 16 ? 16 : tokens[i].size;
3677 i = cgltf_parse_json_float_array(tokens, i, json_chunk, out_accessor->min, min_size);
3678 }
3679 else if (cgltf_json_strcmp(tokens + i, json_chunk, "max") == 0)
3680 {
3681 ++i;
3682 out_accessor->has_max = 1;
3683 // note: we can't parse the precise number of elements since type may not have been computed yet
3684 int max_size = tokens[i].size > 16 ? 16 : tokens[i].size;
3685 i = cgltf_parse_json_float_array(tokens, i, json_chunk, out_accessor->max, max_size);
3686 }
3687 else if (cgltf_json_strcmp(tokens + i, json_chunk, "sparse") == 0)
3688 {
3689 out_accessor->is_sparse = 1;
3690 i = cgltf_parse_json_accessor_sparse(tokens, i + 1, json_chunk, &out_accessor->sparse);
3691 }
3692 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
3693 {
3694 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_accessor->extras);
3695 }
3696 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
3697 {
3698 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_accessor->extensions_count, &out_accessor->extensions);
3699 }
3700 else
3701 {
3702 i = cgltf_skip_json(tokens, i+1);
3703 }
3704
3705 if (i < 0)
3706 {
3707 return i;
3708 }
3709 }
3710
3711 return i;
3712}
3713
3714static int cgltf_parse_json_texture_transform(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_texture_transform* out_texture_transform)
3715{
3716 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3717
3718 int size = tokens[i].size;
3719 ++i;
3720
3721 for (int j = 0; j < size; ++j)
3722 {
3723 CGLTF_CHECK_KEY(tokens[i]);
3724
3725 if (cgltf_json_strcmp(tokens + i, json_chunk, "offset") == 0)
3726 {
3727 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_texture_transform->offset, 2);
3728 }
3729 else if (cgltf_json_strcmp(tokens + i, json_chunk, "rotation") == 0)
3730 {
3731 ++i;
3732 out_texture_transform->rotation = cgltf_json_to_float(tokens + i, json_chunk);
3733 ++i;
3734 }
3735 else if (cgltf_json_strcmp(tokens + i, json_chunk, "scale") == 0)
3736 {
3737 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_texture_transform->scale, 2);
3738 }
3739 else if (cgltf_json_strcmp(tokens + i, json_chunk, "texCoord") == 0)
3740 {
3741 ++i;
3742 out_texture_transform->has_texcoord = 1;
3743 out_texture_transform->texcoord = cgltf_json_to_int(tokens + i, json_chunk);
3744 ++i;
3745 }
3746 else
3747 {
3748 i = cgltf_skip_json(tokens, i + 1);
3749 }
3750
3751 if (i < 0)
3752 {
3753 return i;
3754 }
3755 }
3756
3757 return i;
3758}
3759
3760static int cgltf_parse_json_texture_view(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_texture_view* out_texture_view)
3761{
3762 (void)options;
3763
3764 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3765
3766 out_texture_view->scale = 1.0f;
3767 cgltf_fill_float_array(out_texture_view->transform.scale, 2, 1.0f);
3768
3769 int size = tokens[i].size;
3770 ++i;
3771
3772 for (int j = 0; j < size; ++j)
3773 {
3774 CGLTF_CHECK_KEY(tokens[i]);
3775
3776 if (cgltf_json_strcmp(tokens + i, json_chunk, "index") == 0)
3777 {
3778 ++i;
3779 out_texture_view->texture = CGLTF_PTRINDEX(cgltf_texture, cgltf_json_to_int(tokens + i, json_chunk));
3780 ++i;
3781 }
3782 else if (cgltf_json_strcmp(tokens + i, json_chunk, "texCoord") == 0)
3783 {
3784 ++i;
3785 out_texture_view->texcoord = cgltf_json_to_int(tokens + i, json_chunk);
3786 ++i;
3787 }
3788 else if (cgltf_json_strcmp(tokens + i, json_chunk, "scale") == 0)
3789 {
3790 ++i;
3791 out_texture_view->scale = cgltf_json_to_float(tokens + i, json_chunk);
3792 ++i;
3793 }
3794 else if (cgltf_json_strcmp(tokens + i, json_chunk, "strength") == 0)
3795 {
3796 ++i;
3797 out_texture_view->scale = cgltf_json_to_float(tokens + i, json_chunk);
3798 ++i;
3799 }
3800 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
3801 {
3802 ++i;
3803
3804 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3805 int extensions_size = tokens[i].size;
3806
3807 ++i;
3808
3809 for (int k = 0; k < extensions_size; ++k)
3810 {
3811 CGLTF_CHECK_KEY(tokens[i]);
3812
3813 if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_texture_transform") == 0)
3814 {
3815 out_texture_view->has_transform = 1;
3816 i = cgltf_parse_json_texture_transform(tokens, i + 1, json_chunk, &out_texture_view->transform);
3817 }
3818 else
3819 {
3820 i = cgltf_skip_json(tokens, i + 1);
3821 }
3822
3823 if (i < 0)
3824 {
3825 return i;
3826 }
3827 }
3828 }
3829 else
3830 {
3831 i = cgltf_skip_json(tokens, i + 1);
3832 }
3833
3834 if (i < 0)
3835 {
3836 return i;
3837 }
3838 }
3839
3840 return i;
3841}
3842
3843static int cgltf_parse_json_pbr_metallic_roughness(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_pbr_metallic_roughness* out_pbr)
3844{
3845 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3846
3847 int size = tokens[i].size;
3848 ++i;
3849
3850 for (int j = 0; j < size; ++j)
3851 {
3852 CGLTF_CHECK_KEY(tokens[i]);
3853
3854 if (cgltf_json_strcmp(tokens+i, json_chunk, "metallicFactor") == 0)
3855 {
3856 ++i;
3857 out_pbr->metallic_factor =
3858 cgltf_json_to_float(tokens + i, json_chunk);
3859 ++i;
3860 }
3861 else if (cgltf_json_strcmp(tokens+i, json_chunk, "roughnessFactor") == 0)
3862 {
3863 ++i;
3864 out_pbr->roughness_factor =
3865 cgltf_json_to_float(tokens+i, json_chunk);
3866 ++i;
3867 }
3868 else if (cgltf_json_strcmp(tokens+i, json_chunk, "baseColorFactor") == 0)
3869 {
3870 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_pbr->base_color_factor, 4);
3871 }
3872 else if (cgltf_json_strcmp(tokens+i, json_chunk, "baseColorTexture") == 0)
3873 {
3874 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_pbr->base_color_texture);
3875 }
3876 else if (cgltf_json_strcmp(tokens + i, json_chunk, "metallicRoughnessTexture") == 0)
3877 {
3878 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_pbr->metallic_roughness_texture);
3879 }
3880 else
3881 {
3882 i = cgltf_skip_json(tokens, i+1);
3883 }
3884
3885 if (i < 0)
3886 {
3887 return i;
3888 }
3889 }
3890
3891 return i;
3892}
3893
3894static int cgltf_parse_json_pbr_specular_glossiness(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_pbr_specular_glossiness* out_pbr)
3895{
3896 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3897 int size = tokens[i].size;
3898 ++i;
3899
3900 for (int j = 0; j < size; ++j)
3901 {
3902 CGLTF_CHECK_KEY(tokens[i]);
3903
3904 if (cgltf_json_strcmp(tokens+i, json_chunk, "diffuseFactor") == 0)
3905 {
3906 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_pbr->diffuse_factor, 4);
3907 }
3908 else if (cgltf_json_strcmp(tokens+i, json_chunk, "specularFactor") == 0)
3909 {
3910 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_pbr->specular_factor, 3);
3911 }
3912 else if (cgltf_json_strcmp(tokens+i, json_chunk, "glossinessFactor") == 0)
3913 {
3914 ++i;
3915 out_pbr->glossiness_factor = cgltf_json_to_float(tokens + i, json_chunk);
3916 ++i;
3917 }
3918 else if (cgltf_json_strcmp(tokens+i, json_chunk, "diffuseTexture") == 0)
3919 {
3920 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_pbr->diffuse_texture);
3921 }
3922 else if (cgltf_json_strcmp(tokens+i, json_chunk, "specularGlossinessTexture") == 0)
3923 {
3924 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_pbr->specular_glossiness_texture);
3925 }
3926 else
3927 {
3928 i = cgltf_skip_json(tokens, i+1);
3929 }
3930
3931 if (i < 0)
3932 {
3933 return i;
3934 }
3935 }
3936
3937 return i;
3938}
3939
3940static int cgltf_parse_json_clearcoat(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_clearcoat* out_clearcoat)
3941{
3942 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3943 int size = tokens[i].size;
3944 ++i;
3945
3946 for (int j = 0; j < size; ++j)
3947 {
3948 CGLTF_CHECK_KEY(tokens[i]);
3949
3950 if (cgltf_json_strcmp(tokens+i, json_chunk, "clearcoatFactor") == 0)
3951 {
3952 ++i;
3953 out_clearcoat->clearcoat_factor = cgltf_json_to_float(tokens + i, json_chunk);
3954 ++i;
3955 }
3956 else if (cgltf_json_strcmp(tokens+i, json_chunk, "clearcoatRoughnessFactor") == 0)
3957 {
3958 ++i;
3959 out_clearcoat->clearcoat_roughness_factor = cgltf_json_to_float(tokens + i, json_chunk);
3960 ++i;
3961 }
3962 else if (cgltf_json_strcmp(tokens+i, json_chunk, "clearcoatTexture") == 0)
3963 {
3964 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_clearcoat->clearcoat_texture);
3965 }
3966 else if (cgltf_json_strcmp(tokens+i, json_chunk, "clearcoatRoughnessTexture") == 0)
3967 {
3968 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_clearcoat->clearcoat_roughness_texture);
3969 }
3970 else if (cgltf_json_strcmp(tokens+i, json_chunk, "clearcoatNormalTexture") == 0)
3971 {
3972 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_clearcoat->clearcoat_normal_texture);
3973 }
3974 else
3975 {
3976 i = cgltf_skip_json(tokens, i+1);
3977 }
3978
3979 if (i < 0)
3980 {
3981 return i;
3982 }
3983 }
3984
3985 return i;
3986}
3987
3988static int cgltf_parse_json_ior(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_ior* out_ior)
3989{
3990 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
3991 int size = tokens[i].size;
3992 ++i;
3993
3994 // Default values
3995 out_ior->ior = 1.5f;
3996
3997 for (int j = 0; j < size; ++j)
3998 {
3999 CGLTF_CHECK_KEY(tokens[i]);
4000
4001 if (cgltf_json_strcmp(tokens+i, json_chunk, "ior") == 0)
4002 {
4003 ++i;
4004 out_ior->ior = cgltf_json_to_float(tokens + i, json_chunk);
4005 ++i;
4006 }
4007 else
4008 {
4009 i = cgltf_skip_json(tokens, i+1);
4010 }
4011
4012 if (i < 0)
4013 {
4014 return i;
4015 }
4016 }
4017
4018 return i;
4019}
4020
4021static int cgltf_parse_json_specular(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_specular* out_specular)
4022{
4023 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4024 int size = tokens[i].size;
4025 ++i;
4026
4027 // Default values
4028 out_specular->specular_factor = 1.0f;
4029 cgltf_fill_float_array(out_specular->specular_color_factor, 3, 1.0f);
4030
4031 for (int j = 0; j < size; ++j)
4032 {
4033 CGLTF_CHECK_KEY(tokens[i]);
4034
4035 if (cgltf_json_strcmp(tokens+i, json_chunk, "specularFactor") == 0)
4036 {
4037 ++i;
4038 out_specular->specular_factor = cgltf_json_to_float(tokens + i, json_chunk);
4039 ++i;
4040 }
4041 else if (cgltf_json_strcmp(tokens+i, json_chunk, "specularColorFactor") == 0)
4042 {
4043 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_specular->specular_color_factor, 3);
4044 }
4045 else if (cgltf_json_strcmp(tokens+i, json_chunk, "specularTexture") == 0)
4046 {
4047 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_specular->specular_texture);
4048 }
4049 else if (cgltf_json_strcmp(tokens + i, json_chunk, "specularColorTexture") == 0)
4050 {
4051 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_specular->specular_color_texture);
4052 }
4053 else
4054 {
4055 i = cgltf_skip_json(tokens, i+1);
4056 }
4057
4058 if (i < 0)
4059 {
4060 return i;
4061 }
4062 }
4063
4064 return i;
4065}
4066
4067static int cgltf_parse_json_transmission(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_transmission* out_transmission)
4068{
4069 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4070 int size = tokens[i].size;
4071 ++i;
4072
4073 for (int j = 0; j < size; ++j)
4074 {
4075 CGLTF_CHECK_KEY(tokens[i]);
4076
4077 if (cgltf_json_strcmp(tokens+i, json_chunk, "transmissionFactor") == 0)
4078 {
4079 ++i;
4080 out_transmission->transmission_factor = cgltf_json_to_float(tokens + i, json_chunk);
4081 ++i;
4082 }
4083 else if (cgltf_json_strcmp(tokens+i, json_chunk, "transmissionTexture") == 0)
4084 {
4085 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_transmission->transmission_texture);
4086 }
4087 else
4088 {
4089 i = cgltf_skip_json(tokens, i+1);
4090 }
4091
4092 if (i < 0)
4093 {
4094 return i;
4095 }
4096 }
4097
4098 return i;
4099}
4100
4101static int cgltf_parse_json_volume(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_volume* out_volume)
4102{
4103 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4104 int size = tokens[i].size;
4105 ++i;
4106
4107 for (int j = 0; j < size; ++j)
4108 {
4109 CGLTF_CHECK_KEY(tokens[i]);
4110
4111 if (cgltf_json_strcmp(tokens + i, json_chunk, "thicknessFactor") == 0)
4112 {
4113 ++i;
4114 out_volume->thickness_factor = cgltf_json_to_float(tokens + i, json_chunk);
4115 ++i;
4116 }
4117 else if (cgltf_json_strcmp(tokens + i, json_chunk, "thicknessTexture") == 0)
4118 {
4119 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_volume->thickness_texture);
4120 }
4121 else if (cgltf_json_strcmp(tokens + i, json_chunk, "attenuationColor") == 0)
4122 {
4123 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_volume->attenuation_color, 3);
4124 }
4125 else if (cgltf_json_strcmp(tokens + i, json_chunk, "attenuationDistance") == 0)
4126 {
4127 ++i;
4128 out_volume->attenuation_distance = cgltf_json_to_float(tokens + i, json_chunk);
4129 ++i;
4130 }
4131 else
4132 {
4133 i = cgltf_skip_json(tokens, i + 1);
4134 }
4135
4136 if (i < 0)
4137 {
4138 return i;
4139 }
4140 }
4141
4142 return i;
4143}
4144
4145static int cgltf_parse_json_sheen(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_sheen* out_sheen)
4146{
4147 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4148 int size = tokens[i].size;
4149 ++i;
4150
4151 for (int j = 0; j < size; ++j)
4152 {
4153 CGLTF_CHECK_KEY(tokens[i]);
4154
4155 if (cgltf_json_strcmp(tokens+i, json_chunk, "sheenColorFactor") == 0)
4156 {
4157 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_sheen->sheen_color_factor, 3);
4158 }
4159 else if (cgltf_json_strcmp(tokens+i, json_chunk, "sheenColorTexture") == 0)
4160 {
4161 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_sheen->sheen_color_texture);
4162 }
4163 else if (cgltf_json_strcmp(tokens+i, json_chunk, "sheenRoughnessFactor") == 0)
4164 {
4165 ++i;
4166 out_sheen->sheen_roughness_factor = cgltf_json_to_float(tokens + i, json_chunk);
4167 ++i;
4168 }
4169 else if (cgltf_json_strcmp(tokens+i, json_chunk, "sheenRoughnessTexture") == 0)
4170 {
4171 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_sheen->sheen_roughness_texture);
4172 }
4173 else
4174 {
4175 i = cgltf_skip_json(tokens, i+1);
4176 }
4177
4178 if (i < 0)
4179 {
4180 return i;
4181 }
4182 }
4183
4184 return i;
4185}
4186
4187static int cgltf_parse_json_emissive_strength(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_emissive_strength* out_emissive_strength)
4188{
4189 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4190 int size = tokens[i].size;
4191 ++i;
4192
4193 // Default
4194 out_emissive_strength->emissive_strength = 1.f;
4195
4196 for (int j = 0; j < size; ++j)
4197 {
4198 CGLTF_CHECK_KEY(tokens[i]);
4199
4200 if (cgltf_json_strcmp(tokens + i, json_chunk, "emissiveStrength") == 0)
4201 {
4202 ++i;
4203 out_emissive_strength->emissive_strength = cgltf_json_to_float(tokens + i, json_chunk);
4204 ++i;
4205 }
4206 else
4207 {
4208 i = cgltf_skip_json(tokens, i + 1);
4209 }
4210
4211 if (i < 0)
4212 {
4213 return i;
4214 }
4215 }
4216
4217 return i;
4218}
4219
4220static int cgltf_parse_json_iridescence(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_iridescence* out_iridescence)
4221{
4222 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4223 int size = tokens[i].size;
4224 ++i;
4225
4226 // Default
4227 out_iridescence->iridescence_ior = 1.3f;
4228 out_iridescence->iridescence_thickness_min = 100.f;
4229 out_iridescence->iridescence_thickness_max = 400.f;
4230
4231 for (int j = 0; j < size; ++j)
4232 {
4233 CGLTF_CHECK_KEY(tokens[i]);
4234
4235 if (cgltf_json_strcmp(tokens + i, json_chunk, "iridescenceFactor") == 0)
4236 {
4237 ++i;
4238 out_iridescence->iridescence_factor = cgltf_json_to_float(tokens + i, json_chunk);
4239 ++i;
4240 }
4241 else if (cgltf_json_strcmp(tokens + i, json_chunk, "iridescenceTexture") == 0)
4242 {
4243 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_iridescence->iridescence_texture);
4244 }
4245 else if (cgltf_json_strcmp(tokens + i, json_chunk, "iridescenceIor") == 0)
4246 {
4247 ++i;
4248 out_iridescence->iridescence_ior = cgltf_json_to_float(tokens + i, json_chunk);
4249 ++i;
4250 }
4251 else if (cgltf_json_strcmp(tokens + i, json_chunk, "iridescenceThicknessMinimum") == 0)
4252 {
4253 ++i;
4254 out_iridescence->iridescence_thickness_min = cgltf_json_to_float(tokens + i, json_chunk);
4255 ++i;
4256 }
4257 else if (cgltf_json_strcmp(tokens + i, json_chunk, "iridescenceThicknessMaximum") == 0)
4258 {
4259 ++i;
4260 out_iridescence->iridescence_thickness_max = cgltf_json_to_float(tokens + i, json_chunk);
4261 ++i;
4262 }
4263 else if (cgltf_json_strcmp(tokens + i, json_chunk, "iridescenceThicknessTexture") == 0)
4264 {
4265 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_iridescence->iridescence_thickness_texture);
4266 }
4267 else
4268 {
4269 i = cgltf_skip_json(tokens, i + 1);
4270 }
4271
4272 if (i < 0)
4273 {
4274 return i;
4275 }
4276 }
4277
4278 return i;
4279}
4280
4281static int cgltf_parse_json_anisotropy(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_anisotropy* out_anisotropy)
4282{
4283 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4284 int size = tokens[i].size;
4285 ++i;
4286
4287
4288 for (int j = 0; j < size; ++j)
4289 {
4290 CGLTF_CHECK_KEY(tokens[i]);
4291
4292 if (cgltf_json_strcmp(tokens + i, json_chunk, "anisotropyStrength") == 0)
4293 {
4294 ++i;
4295 out_anisotropy->anisotropy_strength = cgltf_json_to_float(tokens + i, json_chunk);
4296 ++i;
4297 }
4298 else if (cgltf_json_strcmp(tokens + i, json_chunk, "anisotropyRotation") == 0)
4299 {
4300 ++i;
4301 out_anisotropy->anisotropy_rotation = cgltf_json_to_float(tokens + i, json_chunk);
4302 ++i;
4303 }
4304 else if (cgltf_json_strcmp(tokens + i, json_chunk, "anisotropyTexture") == 0)
4305 {
4306 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk, &out_anisotropy->anisotropy_texture);
4307 }
4308 else
4309 {
4310 i = cgltf_skip_json(tokens, i + 1);
4311 }
4312
4313 if (i < 0)
4314 {
4315 return i;
4316 }
4317 }
4318
4319 return i;
4320}
4321
4322static int cgltf_parse_json_dispersion(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_dispersion* out_dispersion)
4323{
4324 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4325 int size = tokens[i].size;
4326 ++i;
4327
4328
4329 for (int j = 0; j < size; ++j)
4330 {
4331 CGLTF_CHECK_KEY(tokens[i]);
4332
4333 if (cgltf_json_strcmp(tokens + i, json_chunk, "dispersion") == 0)
4334 {
4335 ++i;
4336 out_dispersion->dispersion = cgltf_json_to_float(tokens + i, json_chunk);
4337 ++i;
4338 }
4339 else
4340 {
4341 i = cgltf_skip_json(tokens, i + 1);
4342 }
4343
4344 if (i < 0)
4345 {
4346 return i;
4347 }
4348 }
4349
4350 return i;
4351}
4352
4353static int cgltf_parse_json_image(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_image* out_image)
4354{
4355 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4356
4357 int size = tokens[i].size;
4358 ++i;
4359
4360 for (int j = 0; j < size; ++j)
4361 {
4362 CGLTF_CHECK_KEY(tokens[i]);
4363
4364 if (cgltf_json_strcmp(tokens + i, json_chunk, "uri") == 0)
4365 {
4366 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_image->uri);
4367 }
4368 else if (cgltf_json_strcmp(tokens+i, json_chunk, "bufferView") == 0)
4369 {
4370 ++i;
4371 out_image->buffer_view = CGLTF_PTRINDEX(cgltf_buffer_view, cgltf_json_to_int(tokens + i, json_chunk));
4372 ++i;
4373 }
4374 else if (cgltf_json_strcmp(tokens + i, json_chunk, "mimeType") == 0)
4375 {
4376 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_image->mime_type);
4377 }
4378 else if (cgltf_json_strcmp(tokens + i, json_chunk, "name") == 0)
4379 {
4380 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_image->name);
4381 }
4382 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
4383 {
4384 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_image->extras);
4385 }
4386 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
4387 {
4388 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_image->extensions_count, &out_image->extensions);
4389 }
4390 else
4391 {
4392 i = cgltf_skip_json(tokens, i + 1);
4393 }
4394
4395 if (i < 0)
4396 {
4397 return i;
4398 }
4399 }
4400
4401 return i;
4402}
4403
4404static int cgltf_parse_json_sampler(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_sampler* out_sampler)
4405{
4406 (void)options;
4407 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4408
4409 out_sampler->wrap_s = 10497;
4410 out_sampler->wrap_t = 10497;
4411
4412 int size = tokens[i].size;
4413 ++i;
4414
4415 for (int j = 0; j < size; ++j)
4416 {
4417 CGLTF_CHECK_KEY(tokens[i]);
4418
4419 if (cgltf_json_strcmp(tokens + i, json_chunk, "name") == 0)
4420 {
4421 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_sampler->name);
4422 }
4423 else if (cgltf_json_strcmp(tokens + i, json_chunk, "magFilter") == 0)
4424 {
4425 ++i;
4426 out_sampler->mag_filter
4427 = cgltf_json_to_int(tokens + i, json_chunk);
4428 ++i;
4429 }
4430 else if (cgltf_json_strcmp(tokens + i, json_chunk, "minFilter") == 0)
4431 {
4432 ++i;
4433 out_sampler->min_filter
4434 = cgltf_json_to_int(tokens + i, json_chunk);
4435 ++i;
4436 }
4437 else if (cgltf_json_strcmp(tokens + i, json_chunk, "wrapS") == 0)
4438 {
4439 ++i;
4440 out_sampler->wrap_s
4441 = cgltf_json_to_int(tokens + i, json_chunk);
4442 ++i;
4443 }
4444 else if (cgltf_json_strcmp(tokens + i, json_chunk, "wrapT") == 0)
4445 {
4446 ++i;
4447 out_sampler->wrap_t
4448 = cgltf_json_to_int(tokens + i, json_chunk);
4449 ++i;
4450 }
4451 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
4452 {
4453 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sampler->extras);
4454 }
4455 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
4456 {
4457 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_sampler->extensions_count, &out_sampler->extensions);
4458 }
4459 else
4460 {
4461 i = cgltf_skip_json(tokens, i + 1);
4462 }
4463
4464 if (i < 0)
4465 {
4466 return i;
4467 }
4468 }
4469
4470 return i;
4471}
4472
4473static int cgltf_parse_json_texture(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_texture* out_texture)
4474{
4475 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4476
4477 int size = tokens[i].size;
4478 ++i;
4479
4480 for (int j = 0; j < size; ++j)
4481 {
4482 CGLTF_CHECK_KEY(tokens[i]);
4483
4484 if (cgltf_json_strcmp(tokens+i, json_chunk, "name") == 0)
4485 {
4486 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_texture->name);
4487 }
4488 else if (cgltf_json_strcmp(tokens + i, json_chunk, "sampler") == 0)
4489 {
4490 ++i;
4491 out_texture->sampler = CGLTF_PTRINDEX(cgltf_sampler, cgltf_json_to_int(tokens + i, json_chunk));
4492 ++i;
4493 }
4494 else if (cgltf_json_strcmp(tokens + i, json_chunk, "source") == 0)
4495 {
4496 ++i;
4497 out_texture->image = CGLTF_PTRINDEX(cgltf_image, cgltf_json_to_int(tokens + i, json_chunk));
4498 ++i;
4499 }
4500 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
4501 {
4502 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_texture->extras);
4503 }
4504 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
4505 {
4506 ++i;
4507
4508 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4509 if (out_texture->extensions)
4510 {
4511 return CGLTF_ERROR_JSON;
4512 }
4513
4514 int extensions_size = tokens[i].size;
4515 ++i;
4516 out_texture->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size);
4517 out_texture->extensions_count = 0;
4518
4519 if (!out_texture->extensions)
4520 {
4521 return CGLTF_ERROR_NOMEM;
4522 }
4523
4524 for (int k = 0; k < extensions_size; ++k)
4525 {
4526 CGLTF_CHECK_KEY(tokens[i]);
4527
4528 if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_texture_basisu") == 0)
4529 {
4530 out_texture->has_basisu = 1;
4531 ++i;
4532 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4533 int num_properties = tokens[i].size;
4534 ++i;
4535
4536 for (int t = 0; t < num_properties; ++t)
4537 {
4538 CGLTF_CHECK_KEY(tokens[i]);
4539
4540 if (cgltf_json_strcmp(tokens + i, json_chunk, "source") == 0)
4541 {
4542 ++i;
4543 out_texture->basisu_image = CGLTF_PTRINDEX(cgltf_image, cgltf_json_to_int(tokens + i, json_chunk));
4544 ++i;
4545 }
4546 else
4547 {
4548 i = cgltf_skip_json(tokens, i + 1);
4549 }
4550 if (i < 0)
4551 {
4552 return i;
4553 }
4554 }
4555 }
4556 else if (cgltf_json_strcmp(tokens + i, json_chunk, "EXT_texture_webp") == 0)
4557 {
4558 out_texture->has_webp = 1;
4559 ++i;
4560 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4561 int num_properties = tokens[i].size;
4562 ++i;
4563
4564 for (int t = 0; t < num_properties; ++t)
4565 {
4566 CGLTF_CHECK_KEY(tokens[i]);
4567
4568 if (cgltf_json_strcmp(tokens + i, json_chunk, "source") == 0)
4569 {
4570 ++i;
4571 out_texture->webp_image = CGLTF_PTRINDEX(cgltf_image, cgltf_json_to_int(tokens + i, json_chunk));
4572 ++i;
4573 }
4574 else
4575 {
4576 i = cgltf_skip_json(tokens, i + 1);
4577 }
4578 if (i < 0)
4579 {
4580 return i;
4581 }
4582 }
4583 }
4584 else
4585 {
4586 i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_texture->extensions[out_texture->extensions_count++]));
4587 }
4588
4589 if (i < 0)
4590 {
4591 return i;
4592 }
4593 }
4594 }
4595 else
4596 {
4597 i = cgltf_skip_json(tokens, i + 1);
4598 }
4599
4600 if (i < 0)
4601 {
4602 return i;
4603 }
4604 }
4605
4606 return i;
4607}
4608
4609static int cgltf_parse_json_material(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_material* out_material)
4610{
4611 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4612
4613 cgltf_fill_float_array(out_material->pbr_metallic_roughness.base_color_factor, 4, 1.0f);
4614 out_material->pbr_metallic_roughness.metallic_factor = 1.0f;
4615 out_material->pbr_metallic_roughness.roughness_factor = 1.0f;
4616
4617 cgltf_fill_float_array(out_material->pbr_specular_glossiness.diffuse_factor, 4, 1.0f);
4618 cgltf_fill_float_array(out_material->pbr_specular_glossiness.specular_factor, 3, 1.0f);
4619 out_material->pbr_specular_glossiness.glossiness_factor = 1.0f;
4620
4621 cgltf_fill_float_array(out_material->volume.attenuation_color, 3, 1.0f);
4622 out_material->volume.attenuation_distance = FLT_MAX;
4623
4624 out_material->alpha_cutoff = 0.5f;
4625
4626 int size = tokens[i].size;
4627 ++i;
4628
4629 for (int j = 0; j < size; ++j)
4630 {
4631 CGLTF_CHECK_KEY(tokens[i]);
4632
4633 if (cgltf_json_strcmp(tokens+i, json_chunk, "name") == 0)
4634 {
4635 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_material->name);
4636 }
4637 else if (cgltf_json_strcmp(tokens+i, json_chunk, "pbrMetallicRoughness") == 0)
4638 {
4639 out_material->has_pbr_metallic_roughness = 1;
4640 i = cgltf_parse_json_pbr_metallic_roughness(options, tokens, i + 1, json_chunk, &out_material->pbr_metallic_roughness);
4641 }
4642 else if (cgltf_json_strcmp(tokens+i, json_chunk, "emissiveFactor") == 0)
4643 {
4644 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_material->emissive_factor, 3);
4645 }
4646 else if (cgltf_json_strcmp(tokens + i, json_chunk, "normalTexture") == 0)
4647 {
4648 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk,
4649 &out_material->normal_texture);
4650 }
4651 else if (cgltf_json_strcmp(tokens + i, json_chunk, "occlusionTexture") == 0)
4652 {
4653 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk,
4654 &out_material->occlusion_texture);
4655 }
4656 else if (cgltf_json_strcmp(tokens + i, json_chunk, "emissiveTexture") == 0)
4657 {
4658 i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk,
4659 &out_material->emissive_texture);
4660 }
4661 else if (cgltf_json_strcmp(tokens + i, json_chunk, "alphaMode") == 0)
4662 {
4663 ++i;
4664 if (cgltf_json_strcmp(tokens + i, json_chunk, "OPAQUE") == 0)
4665 {
4666 out_material->alpha_mode = cgltf_alpha_mode_opaque;
4667 }
4668 else if (cgltf_json_strcmp(tokens + i, json_chunk, "MASK") == 0)
4669 {
4670 out_material->alpha_mode = cgltf_alpha_mode_mask;
4671 }
4672 else if (cgltf_json_strcmp(tokens + i, json_chunk, "BLEND") == 0)
4673 {
4674 out_material->alpha_mode = cgltf_alpha_mode_blend;
4675 }
4676 ++i;
4677 }
4678 else if (cgltf_json_strcmp(tokens + i, json_chunk, "alphaCutoff") == 0)
4679 {
4680 ++i;
4681 out_material->alpha_cutoff = cgltf_json_to_float(tokens + i, json_chunk);
4682 ++i;
4683 }
4684 else if (cgltf_json_strcmp(tokens + i, json_chunk, "doubleSided") == 0)
4685 {
4686 ++i;
4687 out_material->double_sided =
4688 cgltf_json_to_bool(tokens + i, json_chunk);
4689 ++i;
4690 }
4691 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
4692 {
4693 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_material->extras);
4694 }
4695 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
4696 {
4697 ++i;
4698
4699 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4700 if(out_material->extensions)
4701 {
4702 return CGLTF_ERROR_JSON;
4703 }
4704
4705 int extensions_size = tokens[i].size;
4706 ++i;
4707 out_material->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size);
4708 out_material->extensions_count= 0;
4709
4710 if (!out_material->extensions)
4711 {
4712 return CGLTF_ERROR_NOMEM;
4713 }
4714
4715 for (int k = 0; k < extensions_size; ++k)
4716 {
4717 CGLTF_CHECK_KEY(tokens[i]);
4718
4719 if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_pbrSpecularGlossiness") == 0)
4720 {
4721 out_material->has_pbr_specular_glossiness = 1;
4722 i = cgltf_parse_json_pbr_specular_glossiness(options, tokens, i + 1, json_chunk, &out_material->pbr_specular_glossiness);
4723 }
4724 else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_unlit") == 0)
4725 {
4726 out_material->unlit = 1;
4727 i = cgltf_skip_json(tokens, i+1);
4728 }
4729 else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_clearcoat") == 0)
4730 {
4731 out_material->has_clearcoat = 1;
4732 i = cgltf_parse_json_clearcoat(options, tokens, i + 1, json_chunk, &out_material->clearcoat);
4733 }
4734 else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_ior") == 0)
4735 {
4736 out_material->has_ior = 1;
4737 i = cgltf_parse_json_ior(tokens, i + 1, json_chunk, &out_material->ior);
4738 }
4739 else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_specular") == 0)
4740 {
4741 out_material->has_specular = 1;
4742 i = cgltf_parse_json_specular(options, tokens, i + 1, json_chunk, &out_material->specular);
4743 }
4744 else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_transmission") == 0)
4745 {
4746 out_material->has_transmission = 1;
4747 i = cgltf_parse_json_transmission(options, tokens, i + 1, json_chunk, &out_material->transmission);
4748 }
4749 else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_materials_volume") == 0)
4750 {
4751 out_material->has_volume = 1;
4752 i = cgltf_parse_json_volume(options, tokens, i + 1, json_chunk, &out_material->volume);
4753 }
4754 else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_sheen") == 0)
4755 {
4756 out_material->has_sheen = 1;
4757 i = cgltf_parse_json_sheen(options, tokens, i + 1, json_chunk, &out_material->sheen);
4758 }
4759 else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_materials_emissive_strength") == 0)
4760 {
4761 out_material->has_emissive_strength = 1;
4762 i = cgltf_parse_json_emissive_strength(tokens, i + 1, json_chunk, &out_material->emissive_strength);
4763 }
4764 else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_materials_iridescence") == 0)
4765 {
4766 out_material->has_iridescence = 1;
4767 i = cgltf_parse_json_iridescence(options, tokens, i + 1, json_chunk, &out_material->iridescence);
4768 }
4769 else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_materials_anisotropy") == 0)
4770 {
4771 out_material->has_anisotropy = 1;
4772 i = cgltf_parse_json_anisotropy(options, tokens, i + 1, json_chunk, &out_material->anisotropy);
4773 }
4774 else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_materials_dispersion") == 0)
4775 {
4776 out_material->has_dispersion = 1;
4777 i = cgltf_parse_json_dispersion(tokens, i + 1, json_chunk, &out_material->dispersion);
4778 }
4779 else
4780 {
4781 i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_material->extensions[out_material->extensions_count++]));
4782 }
4783
4784 if (i < 0)
4785 {
4786 return i;
4787 }
4788 }
4789 }
4790 else
4791 {
4792 i = cgltf_skip_json(tokens, i+1);
4793 }
4794
4795 if (i < 0)
4796 {
4797 return i;
4798 }
4799 }
4800
4801 return i;
4802}
4803
4804static int cgltf_parse_json_accessors(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
4805{
4806 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_accessor), (void**)&out_data->accessors, &out_data->accessors_count);
4807 if (i < 0)
4808 {
4809 return i;
4810 }
4811
4812 for (cgltf_size j = 0; j < out_data->accessors_count; ++j)
4813 {
4814 i = cgltf_parse_json_accessor(options, tokens, i, json_chunk, &out_data->accessors[j]);
4815 if (i < 0)
4816 {
4817 return i;
4818 }
4819 }
4820 return i;
4821}
4822
4823static int cgltf_parse_json_materials(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
4824{
4825 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_material), (void**)&out_data->materials, &out_data->materials_count);
4826 if (i < 0)
4827 {
4828 return i;
4829 }
4830
4831 for (cgltf_size j = 0; j < out_data->materials_count; ++j)
4832 {
4833 i = cgltf_parse_json_material(options, tokens, i, json_chunk, &out_data->materials[j]);
4834 if (i < 0)
4835 {
4836 return i;
4837 }
4838 }
4839 return i;
4840}
4841
4842static int cgltf_parse_json_images(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
4843{
4844 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_image), (void**)&out_data->images, &out_data->images_count);
4845 if (i < 0)
4846 {
4847 return i;
4848 }
4849
4850 for (cgltf_size j = 0; j < out_data->images_count; ++j)
4851 {
4852 i = cgltf_parse_json_image(options, tokens, i, json_chunk, &out_data->images[j]);
4853 if (i < 0)
4854 {
4855 return i;
4856 }
4857 }
4858 return i;
4859}
4860
4861static int cgltf_parse_json_textures(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
4862{
4863 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_texture), (void**)&out_data->textures, &out_data->textures_count);
4864 if (i < 0)
4865 {
4866 return i;
4867 }
4868
4869 for (cgltf_size j = 0; j < out_data->textures_count; ++j)
4870 {
4871 i = cgltf_parse_json_texture(options, tokens, i, json_chunk, &out_data->textures[j]);
4872 if (i < 0)
4873 {
4874 return i;
4875 }
4876 }
4877 return i;
4878}
4879
4880static int cgltf_parse_json_samplers(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
4881{
4882 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_sampler), (void**)&out_data->samplers, &out_data->samplers_count);
4883 if (i < 0)
4884 {
4885 return i;
4886 }
4887
4888 for (cgltf_size j = 0; j < out_data->samplers_count; ++j)
4889 {
4890 i = cgltf_parse_json_sampler(options, tokens, i, json_chunk, &out_data->samplers[j]);
4891 if (i < 0)
4892 {
4893 return i;
4894 }
4895 }
4896 return i;
4897}
4898
4899static int cgltf_parse_json_meshopt_compression(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_meshopt_compression* out_meshopt_compression)
4900{
4901 (void)options;
4902 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4903
4904 int size = tokens[i].size;
4905 ++i;
4906
4907 for (int j = 0; j < size; ++j)
4908 {
4909 CGLTF_CHECK_KEY(tokens[i]);
4910
4911 if (cgltf_json_strcmp(tokens+i, json_chunk, "buffer") == 0)
4912 {
4913 ++i;
4914 out_meshopt_compression->buffer = CGLTF_PTRINDEX(cgltf_buffer, cgltf_json_to_int(tokens + i, json_chunk));
4915 ++i;
4916 }
4917 else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteOffset") == 0)
4918 {
4919 ++i;
4920 out_meshopt_compression->offset = cgltf_json_to_size(tokens+i, json_chunk);
4921 ++i;
4922 }
4923 else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteLength") == 0)
4924 {
4925 ++i;
4926 out_meshopt_compression->size = cgltf_json_to_size(tokens+i, json_chunk);
4927 ++i;
4928 }
4929 else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteStride") == 0)
4930 {
4931 ++i;
4932 out_meshopt_compression->stride = cgltf_json_to_size(tokens+i, json_chunk);
4933 ++i;
4934 }
4935 else if (cgltf_json_strcmp(tokens+i, json_chunk, "count") == 0)
4936 {
4937 ++i;
4938 out_meshopt_compression->count = cgltf_json_to_size(tokens+i, json_chunk);
4939 ++i;
4940 }
4941 else if (cgltf_json_strcmp(tokens+i, json_chunk, "mode") == 0)
4942 {
4943 ++i;
4944 if (cgltf_json_strcmp(tokens+i, json_chunk, "ATTRIBUTES") == 0)
4945 {
4946 out_meshopt_compression->mode = cgltf_meshopt_compression_mode_attributes;
4947 }
4948 else if (cgltf_json_strcmp(tokens+i, json_chunk, "TRIANGLES") == 0)
4949 {
4950 out_meshopt_compression->mode = cgltf_meshopt_compression_mode_triangles;
4951 }
4952 else if (cgltf_json_strcmp(tokens+i, json_chunk, "INDICES") == 0)
4953 {
4954 out_meshopt_compression->mode = cgltf_meshopt_compression_mode_indices;
4955 }
4956 ++i;
4957 }
4958 else if (cgltf_json_strcmp(tokens+i, json_chunk, "filter") == 0)
4959 {
4960 ++i;
4961 if (cgltf_json_strcmp(tokens+i, json_chunk, "NONE") == 0)
4962 {
4963 out_meshopt_compression->filter = cgltf_meshopt_compression_filter_none;
4964 }
4965 else if (cgltf_json_strcmp(tokens+i, json_chunk, "OCTAHEDRAL") == 0)
4966 {
4967 out_meshopt_compression->filter = cgltf_meshopt_compression_filter_octahedral;
4968 }
4969 else if (cgltf_json_strcmp(tokens+i, json_chunk, "QUATERNION") == 0)
4970 {
4971 out_meshopt_compression->filter = cgltf_meshopt_compression_filter_quaternion;
4972 }
4973 else if (cgltf_json_strcmp(tokens+i, json_chunk, "EXPONENTIAL") == 0)
4974 {
4975 out_meshopt_compression->filter = cgltf_meshopt_compression_filter_exponential;
4976 }
4977 ++i;
4978 }
4979 else
4980 {
4981 i = cgltf_skip_json(tokens, i+1);
4982 }
4983
4984 if (i < 0)
4985 {
4986 return i;
4987 }
4988 }
4989
4990 return i;
4991}
4992
4993static int cgltf_parse_json_buffer_view(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_buffer_view* out_buffer_view)
4994{
4995 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
4996
4997 int size = tokens[i].size;
4998 ++i;
4999
5000 for (int j = 0; j < size; ++j)
5001 {
5002 CGLTF_CHECK_KEY(tokens[i]);
5003
5004 if (cgltf_json_strcmp(tokens + i, json_chunk, "name") == 0)
5005 {
5006 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_buffer_view->name);
5007 }
5008 else if (cgltf_json_strcmp(tokens+i, json_chunk, "buffer") == 0)
5009 {
5010 ++i;
5011 out_buffer_view->buffer = CGLTF_PTRINDEX(cgltf_buffer, cgltf_json_to_int(tokens + i, json_chunk));
5012 ++i;
5013 }
5014 else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteOffset") == 0)
5015 {
5016 ++i;
5017 out_buffer_view->offset =
5018 cgltf_json_to_size(tokens+i, json_chunk);
5019 ++i;
5020 }
5021 else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteLength") == 0)
5022 {
5023 ++i;
5024 out_buffer_view->size =
5025 cgltf_json_to_size(tokens+i, json_chunk);
5026 ++i;
5027 }
5028 else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteStride") == 0)
5029 {
5030 ++i;
5031 out_buffer_view->stride =
5032 cgltf_json_to_size(tokens+i, json_chunk);
5033 ++i;
5034 }
5035 else if (cgltf_json_strcmp(tokens+i, json_chunk, "target") == 0)
5036 {
5037 ++i;
5038 int type = cgltf_json_to_int(tokens+i, json_chunk);
5039 switch (type)
5040 {
5041 case 34962:
5042 type = cgltf_buffer_view_type_vertices;
5043 break;
5044 case 34963:
5045 type = cgltf_buffer_view_type_indices;
5046 break;
5047 default:
5048 type = cgltf_buffer_view_type_invalid;
5049 break;
5050 }
5051 out_buffer_view->type = (cgltf_buffer_view_type)type;
5052 ++i;
5053 }
5054 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
5055 {
5056 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_buffer_view->extras);
5057 }
5058 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
5059 {
5060 ++i;
5061
5062 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5063 if(out_buffer_view->extensions)
5064 {
5065 return CGLTF_ERROR_JSON;
5066 }
5067
5068 int extensions_size = tokens[i].size;
5069 out_buffer_view->extensions_count = 0;
5070 out_buffer_view->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size);
5071
5072 if (!out_buffer_view->extensions)
5073 {
5074 return CGLTF_ERROR_NOMEM;
5075 }
5076
5077 ++i;
5078 for (int k = 0; k < extensions_size; ++k)
5079 {
5080 CGLTF_CHECK_KEY(tokens[i]);
5081
5082 if (cgltf_json_strcmp(tokens+i, json_chunk, "EXT_meshopt_compression") == 0)
5083 {
5084 out_buffer_view->has_meshopt_compression = 1;
5085 i = cgltf_parse_json_meshopt_compression(options, tokens, i + 1, json_chunk, &out_buffer_view->meshopt_compression);
5086 }
5087 else
5088 {
5089 i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_buffer_view->extensions[out_buffer_view->extensions_count++]));
5090 }
5091
5092 if (i < 0)
5093 {
5094 return i;
5095 }
5096 }
5097 }
5098 else
5099 {
5100 i = cgltf_skip_json(tokens, i+1);
5101 }
5102
5103 if (i < 0)
5104 {
5105 return i;
5106 }
5107 }
5108
5109 return i;
5110}
5111
5112static int cgltf_parse_json_buffer_views(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
5113{
5114 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_buffer_view), (void**)&out_data->buffer_views, &out_data->buffer_views_count);
5115 if (i < 0)
5116 {
5117 return i;
5118 }
5119
5120 for (cgltf_size j = 0; j < out_data->buffer_views_count; ++j)
5121 {
5122 i = cgltf_parse_json_buffer_view(options, tokens, i, json_chunk, &out_data->buffer_views[j]);
5123 if (i < 0)
5124 {
5125 return i;
5126 }
5127 }
5128 return i;
5129}
5130
5131static int cgltf_parse_json_buffer(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_buffer* out_buffer)
5132{
5133 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5134
5135 int size = tokens[i].size;
5136 ++i;
5137
5138 for (int j = 0; j < size; ++j)
5139 {
5140 CGLTF_CHECK_KEY(tokens[i]);
5141
5142 if (cgltf_json_strcmp(tokens + i, json_chunk, "name") == 0)
5143 {
5144 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_buffer->name);
5145 }
5146 else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteLength") == 0)
5147 {
5148 ++i;
5149 out_buffer->size =
5150 cgltf_json_to_size(tokens+i, json_chunk);
5151 ++i;
5152 }
5153 else if (cgltf_json_strcmp(tokens+i, json_chunk, "uri") == 0)
5154 {
5155 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_buffer->uri);
5156 }
5157 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
5158 {
5159 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_buffer->extras);
5160 }
5161 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
5162 {
5163 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_buffer->extensions_count, &out_buffer->extensions);
5164 }
5165 else
5166 {
5167 i = cgltf_skip_json(tokens, i+1);
5168 }
5169
5170 if (i < 0)
5171 {
5172 return i;
5173 }
5174 }
5175
5176 return i;
5177}
5178
5179static int cgltf_parse_json_buffers(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
5180{
5181 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_buffer), (void**)&out_data->buffers, &out_data->buffers_count);
5182 if (i < 0)
5183 {
5184 return i;
5185 }
5186
5187 for (cgltf_size j = 0; j < out_data->buffers_count; ++j)
5188 {
5189 i = cgltf_parse_json_buffer(options, tokens, i, json_chunk, &out_data->buffers[j]);
5190 if (i < 0)
5191 {
5192 return i;
5193 }
5194 }
5195 return i;
5196}
5197
5198static int cgltf_parse_json_skin(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_skin* out_skin)
5199{
5200 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5201
5202 int size = tokens[i].size;
5203 ++i;
5204
5205 for (int j = 0; j < size; ++j)
5206 {
5207 CGLTF_CHECK_KEY(tokens[i]);
5208
5209 if (cgltf_json_strcmp(tokens+i, json_chunk, "name") == 0)
5210 {
5211 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_skin->name);
5212 }
5213 else if (cgltf_json_strcmp(tokens+i, json_chunk, "joints") == 0)
5214 {
5215 i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_node*), (void**)&out_skin->joints, &out_skin->joints_count);
5216 if (i < 0)
5217 {
5218 return i;
5219 }
5220
5221 for (cgltf_size k = 0; k < out_skin->joints_count; ++k)
5222 {
5223 out_skin->joints[k] = CGLTF_PTRINDEX(cgltf_node, cgltf_json_to_int(tokens + i, json_chunk));
5224 ++i;
5225 }
5226 }
5227 else if (cgltf_json_strcmp(tokens+i, json_chunk, "skeleton") == 0)
5228 {
5229 ++i;
5230 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE);
5231 out_skin->skeleton = CGLTF_PTRINDEX(cgltf_node, cgltf_json_to_int(tokens + i, json_chunk));
5232 ++i;
5233 }
5234 else if (cgltf_json_strcmp(tokens+i, json_chunk, "inverseBindMatrices") == 0)
5235 {
5236 ++i;
5237 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE);
5238 out_skin->inverse_bind_matrices = CGLTF_PTRINDEX(cgltf_accessor, cgltf_json_to_int(tokens + i, json_chunk));
5239 ++i;
5240 }
5241 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
5242 {
5243 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_skin->extras);
5244 }
5245 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
5246 {
5247 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_skin->extensions_count, &out_skin->extensions);
5248 }
5249 else
5250 {
5251 i = cgltf_skip_json(tokens, i+1);
5252 }
5253
5254 if (i < 0)
5255 {
5256 return i;
5257 }
5258 }
5259
5260 return i;
5261}
5262
5263static int cgltf_parse_json_skins(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
5264{
5265 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_skin), (void**)&out_data->skins, &out_data->skins_count);
5266 if (i < 0)
5267 {
5268 return i;
5269 }
5270
5271 for (cgltf_size j = 0; j < out_data->skins_count; ++j)
5272 {
5273 i = cgltf_parse_json_skin(options, tokens, i, json_chunk, &out_data->skins[j]);
5274 if (i < 0)
5275 {
5276 return i;
5277 }
5278 }
5279 return i;
5280}
5281
5282static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_camera* out_camera)
5283{
5284 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5285
5286 int size = tokens[i].size;
5287 ++i;
5288
5289 for (int j = 0; j < size; ++j)
5290 {
5291 CGLTF_CHECK_KEY(tokens[i]);
5292
5293 if (cgltf_json_strcmp(tokens+i, json_chunk, "name") == 0)
5294 {
5295 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_camera->name);
5296 }
5297 else if (cgltf_json_strcmp(tokens+i, json_chunk, "perspective") == 0)
5298 {
5299 ++i;
5300
5301 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5302
5303 int data_size = tokens[i].size;
5304 ++i;
5305
5306 if (out_camera->type != cgltf_camera_type_invalid)
5307 {
5308 return CGLTF_ERROR_JSON;
5309 }
5310
5311 out_camera->type = cgltf_camera_type_perspective;
5312
5313 for (int k = 0; k < data_size; ++k)
5314 {
5315 CGLTF_CHECK_KEY(tokens[i]);
5316
5317 if (cgltf_json_strcmp(tokens+i, json_chunk, "aspectRatio") == 0)
5318 {
5319 ++i;
5320 out_camera->data.perspective.has_aspect_ratio = 1;
5321 out_camera->data.perspective.aspect_ratio = cgltf_json_to_float(tokens + i, json_chunk);
5322 ++i;
5323 }
5324 else if (cgltf_json_strcmp(tokens+i, json_chunk, "yfov") == 0)
5325 {
5326 ++i;
5327 out_camera->data.perspective.yfov = cgltf_json_to_float(tokens + i, json_chunk);
5328 ++i;
5329 }
5330 else if (cgltf_json_strcmp(tokens+i, json_chunk, "zfar") == 0)
5331 {
5332 ++i;
5333 out_camera->data.perspective.has_zfar = 1;
5334 out_camera->data.perspective.zfar = cgltf_json_to_float(tokens + i, json_chunk);
5335 ++i;
5336 }
5337 else if (cgltf_json_strcmp(tokens+i, json_chunk, "znear") == 0)
5338 {
5339 ++i;
5340 out_camera->data.perspective.znear = cgltf_json_to_float(tokens + i, json_chunk);
5341 ++i;
5342 }
5343 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
5344 {
5345 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_camera->data.perspective.extras);
5346 }
5347 else
5348 {
5349 i = cgltf_skip_json(tokens, i+1);
5350 }
5351
5352 if (i < 0)
5353 {
5354 return i;
5355 }
5356 }
5357 }
5358 else if (cgltf_json_strcmp(tokens+i, json_chunk, "orthographic") == 0)
5359 {
5360 ++i;
5361
5362 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5363
5364 int data_size = tokens[i].size;
5365 ++i;
5366
5367 if (out_camera->type != cgltf_camera_type_invalid)
5368 {
5369 return CGLTF_ERROR_JSON;
5370 }
5371
5372 out_camera->type = cgltf_camera_type_orthographic;
5373
5374 for (int k = 0; k < data_size; ++k)
5375 {
5376 CGLTF_CHECK_KEY(tokens[i]);
5377
5378 if (cgltf_json_strcmp(tokens+i, json_chunk, "xmag") == 0)
5379 {
5380 ++i;
5381 out_camera->data.orthographic.xmag = cgltf_json_to_float(tokens + i, json_chunk);
5382 ++i;
5383 }
5384 else if (cgltf_json_strcmp(tokens+i, json_chunk, "ymag") == 0)
5385 {
5386 ++i;
5387 out_camera->data.orthographic.ymag = cgltf_json_to_float(tokens + i, json_chunk);
5388 ++i;
5389 }
5390 else if (cgltf_json_strcmp(tokens+i, json_chunk, "zfar") == 0)
5391 {
5392 ++i;
5393 out_camera->data.orthographic.zfar = cgltf_json_to_float(tokens + i, json_chunk);
5394 ++i;
5395 }
5396 else if (cgltf_json_strcmp(tokens+i, json_chunk, "znear") == 0)
5397 {
5398 ++i;
5399 out_camera->data.orthographic.znear = cgltf_json_to_float(tokens + i, json_chunk);
5400 ++i;
5401 }
5402 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
5403 {
5404 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_camera->data.orthographic.extras);
5405 }
5406 else
5407 {
5408 i = cgltf_skip_json(tokens, i+1);
5409 }
5410
5411 if (i < 0)
5412 {
5413 return i;
5414 }
5415 }
5416 }
5417 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
5418 {
5419 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_camera->extras);
5420 }
5421 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
5422 {
5423 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_camera->extensions_count, &out_camera->extensions);
5424 }
5425 else
5426 {
5427 i = cgltf_skip_json(tokens, i+1);
5428 }
5429
5430 if (i < 0)
5431 {
5432 return i;
5433 }
5434 }
5435
5436 return i;
5437}
5438
5439static int cgltf_parse_json_cameras(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
5440{
5441 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_camera), (void**)&out_data->cameras, &out_data->cameras_count);
5442 if (i < 0)
5443 {
5444 return i;
5445 }
5446
5447 for (cgltf_size j = 0; j < out_data->cameras_count; ++j)
5448 {
5449 i = cgltf_parse_json_camera(options, tokens, i, json_chunk, &out_data->cameras[j]);
5450 if (i < 0)
5451 {
5452 return i;
5453 }
5454 }
5455 return i;
5456}
5457
5458static int cgltf_parse_json_light(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_light* out_light)
5459{
5460 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5461
5462 out_light->color[0] = 1.f;
5463 out_light->color[1] = 1.f;
5464 out_light->color[2] = 1.f;
5465 out_light->intensity = 1.f;
5466
5467 out_light->spot_inner_cone_angle = 0.f;
5468 out_light->spot_outer_cone_angle = 3.1415926535f / 4.0f;
5469
5470 int size = tokens[i].size;
5471 ++i;
5472
5473 for (int j = 0; j < size; ++j)
5474 {
5475 CGLTF_CHECK_KEY(tokens[i]);
5476
5477 if (cgltf_json_strcmp(tokens+i, json_chunk, "name") == 0)
5478 {
5479 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_light->name);
5480 }
5481 else if (cgltf_json_strcmp(tokens + i, json_chunk, "color") == 0)
5482 {
5483 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_light->color, 3);
5484 }
5485 else if (cgltf_json_strcmp(tokens + i, json_chunk, "intensity") == 0)
5486 {
5487 ++i;
5488 out_light->intensity = cgltf_json_to_float(tokens + i, json_chunk);
5489 ++i;
5490 }
5491 else if (cgltf_json_strcmp(tokens+i, json_chunk, "type") == 0)
5492 {
5493 ++i;
5494 if (cgltf_json_strcmp(tokens + i, json_chunk, "directional") == 0)
5495 {
5496 out_light->type = cgltf_light_type_directional;
5497 }
5498 else if (cgltf_json_strcmp(tokens + i, json_chunk, "point") == 0)
5499 {
5500 out_light->type = cgltf_light_type_point;
5501 }
5502 else if (cgltf_json_strcmp(tokens + i, json_chunk, "spot") == 0)
5503 {
5504 out_light->type = cgltf_light_type_spot;
5505 }
5506 ++i;
5507 }
5508 else if (cgltf_json_strcmp(tokens + i, json_chunk, "range") == 0)
5509 {
5510 ++i;
5511 out_light->range = cgltf_json_to_float(tokens + i, json_chunk);
5512 ++i;
5513 }
5514 else if (cgltf_json_strcmp(tokens+i, json_chunk, "spot") == 0)
5515 {
5516 ++i;
5517
5518 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5519
5520 int data_size = tokens[i].size;
5521 ++i;
5522
5523 for (int k = 0; k < data_size; ++k)
5524 {
5525 CGLTF_CHECK_KEY(tokens[i]);
5526
5527 if (cgltf_json_strcmp(tokens+i, json_chunk, "innerConeAngle") == 0)
5528 {
5529 ++i;
5530 out_light->spot_inner_cone_angle = cgltf_json_to_float(tokens + i, json_chunk);
5531 ++i;
5532 }
5533 else if (cgltf_json_strcmp(tokens+i, json_chunk, "outerConeAngle") == 0)
5534 {
5535 ++i;
5536 out_light->spot_outer_cone_angle = cgltf_json_to_float(tokens + i, json_chunk);
5537 ++i;
5538 }
5539 else
5540 {
5541 i = cgltf_skip_json(tokens, i+1);
5542 }
5543
5544 if (i < 0)
5545 {
5546 return i;
5547 }
5548 }
5549 }
5550 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
5551 {
5552 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_light->extras);
5553 }
5554 else
5555 {
5556 i = cgltf_skip_json(tokens, i+1);
5557 }
5558
5559 if (i < 0)
5560 {
5561 return i;
5562 }
5563 }
5564
5565 return i;
5566}
5567
5568static int cgltf_parse_json_lights(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
5569{
5570 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_light), (void**)&out_data->lights, &out_data->lights_count);
5571 if (i < 0)
5572 {
5573 return i;
5574 }
5575
5576 for (cgltf_size j = 0; j < out_data->lights_count; ++j)
5577 {
5578 i = cgltf_parse_json_light(options, tokens, i, json_chunk, &out_data->lights[j]);
5579 if (i < 0)
5580 {
5581 return i;
5582 }
5583 }
5584 return i;
5585}
5586
5587static int cgltf_parse_json_node(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_node* out_node)
5588{
5589 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5590
5591 out_node->rotation[3] = 1.0f;
5592 out_node->scale[0] = 1.0f;
5593 out_node->scale[1] = 1.0f;
5594 out_node->scale[2] = 1.0f;
5595 out_node->matrix[0] = 1.0f;
5596 out_node->matrix[5] = 1.0f;
5597 out_node->matrix[10] = 1.0f;
5598 out_node->matrix[15] = 1.0f;
5599
5600 int size = tokens[i].size;
5601 ++i;
5602
5603 for (int j = 0; j < size; ++j)
5604 {
5605 CGLTF_CHECK_KEY(tokens[i]);
5606
5607 if (cgltf_json_strcmp(tokens+i, json_chunk, "name") == 0)
5608 {
5609 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_node->name);
5610 }
5611 else if (cgltf_json_strcmp(tokens+i, json_chunk, "children") == 0)
5612 {
5613 i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_node*), (void**)&out_node->children, &out_node->children_count);
5614 if (i < 0)
5615 {
5616 return i;
5617 }
5618
5619 for (cgltf_size k = 0; k < out_node->children_count; ++k)
5620 {
5621 out_node->children[k] = CGLTF_PTRINDEX(cgltf_node, cgltf_json_to_int(tokens + i, json_chunk));
5622 ++i;
5623 }
5624 }
5625 else if (cgltf_json_strcmp(tokens+i, json_chunk, "mesh") == 0)
5626 {
5627 ++i;
5628 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE);
5629 out_node->mesh = CGLTF_PTRINDEX(cgltf_mesh, cgltf_json_to_int(tokens + i, json_chunk));
5630 ++i;
5631 }
5632 else if (cgltf_json_strcmp(tokens+i, json_chunk, "skin") == 0)
5633 {
5634 ++i;
5635 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE);
5636 out_node->skin = CGLTF_PTRINDEX(cgltf_skin, cgltf_json_to_int(tokens + i, json_chunk));
5637 ++i;
5638 }
5639 else if (cgltf_json_strcmp(tokens+i, json_chunk, "camera") == 0)
5640 {
5641 ++i;
5642 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE);
5643 out_node->camera = CGLTF_PTRINDEX(cgltf_camera, cgltf_json_to_int(tokens + i, json_chunk));
5644 ++i;
5645 }
5646 else if (cgltf_json_strcmp(tokens+i, json_chunk, "translation") == 0)
5647 {
5648 out_node->has_translation = 1;
5649 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_node->translation, 3);
5650 }
5651 else if (cgltf_json_strcmp(tokens+i, json_chunk, "rotation") == 0)
5652 {
5653 out_node->has_rotation = 1;
5654 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_node->rotation, 4);
5655 }
5656 else if (cgltf_json_strcmp(tokens+i, json_chunk, "scale") == 0)
5657 {
5658 out_node->has_scale = 1;
5659 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_node->scale, 3);
5660 }
5661 else if (cgltf_json_strcmp(tokens+i, json_chunk, "matrix") == 0)
5662 {
5663 out_node->has_matrix = 1;
5664 i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_node->matrix, 16);
5665 }
5666 else if (cgltf_json_strcmp(tokens + i, json_chunk, "weights") == 0)
5667 {
5668 i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_float), (void**)&out_node->weights, &out_node->weights_count);
5669 if (i < 0)
5670 {
5671 return i;
5672 }
5673
5674 i = cgltf_parse_json_float_array(tokens, i - 1, json_chunk, out_node->weights, (int)out_node->weights_count);
5675 }
5676 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
5677 {
5678 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_node->extras);
5679 }
5680 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
5681 {
5682 ++i;
5683
5684 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5685 if(out_node->extensions)
5686 {
5687 return CGLTF_ERROR_JSON;
5688 }
5689
5690 int extensions_size = tokens[i].size;
5691 out_node->extensions_count= 0;
5692 out_node->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size);
5693
5694 if (!out_node->extensions)
5695 {
5696 return CGLTF_ERROR_NOMEM;
5697 }
5698
5699 ++i;
5700
5701 for (int k = 0; k < extensions_size; ++k)
5702 {
5703 CGLTF_CHECK_KEY(tokens[i]);
5704
5705 if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_lights_punctual") == 0)
5706 {
5707 ++i;
5708
5709 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5710
5711 int data_size = tokens[i].size;
5712 ++i;
5713
5714 for (int m = 0; m < data_size; ++m)
5715 {
5716 CGLTF_CHECK_KEY(tokens[i]);
5717
5718 if (cgltf_json_strcmp(tokens + i, json_chunk, "light") == 0)
5719 {
5720 ++i;
5721 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE);
5722 out_node->light = CGLTF_PTRINDEX(cgltf_light, cgltf_json_to_int(tokens + i, json_chunk));
5723 ++i;
5724 }
5725 else
5726 {
5727 i = cgltf_skip_json(tokens, i + 1);
5728 }
5729
5730 if (i < 0)
5731 {
5732 return i;
5733 }
5734 }
5735 }
5736 else if (cgltf_json_strcmp(tokens + i, json_chunk, "EXT_mesh_gpu_instancing") == 0)
5737 {
5738 out_node->has_mesh_gpu_instancing = 1;
5739 i = cgltf_parse_json_mesh_gpu_instancing(options, tokens, i + 1, json_chunk, &out_node->mesh_gpu_instancing);
5740 }
5741 else
5742 {
5743 i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_node->extensions[out_node->extensions_count++]));
5744 }
5745
5746 if (i < 0)
5747 {
5748 return i;
5749 }
5750 }
5751 }
5752 else
5753 {
5754 i = cgltf_skip_json(tokens, i+1);
5755 }
5756
5757 if (i < 0)
5758 {
5759 return i;
5760 }
5761 }
5762
5763 return i;
5764}
5765
5766static int cgltf_parse_json_nodes(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
5767{
5768 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_node), (void**)&out_data->nodes, &out_data->nodes_count);
5769 if (i < 0)
5770 {
5771 return i;
5772 }
5773
5774 for (cgltf_size j = 0; j < out_data->nodes_count; ++j)
5775 {
5776 i = cgltf_parse_json_node(options, tokens, i, json_chunk, &out_data->nodes[j]);
5777 if (i < 0)
5778 {
5779 return i;
5780 }
5781 }
5782 return i;
5783}
5784
5785static int cgltf_parse_json_scene(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_scene* out_scene)
5786{
5787 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5788
5789 int size = tokens[i].size;
5790 ++i;
5791
5792 for (int j = 0; j < size; ++j)
5793 {
5794 CGLTF_CHECK_KEY(tokens[i]);
5795
5796 if (cgltf_json_strcmp(tokens+i, json_chunk, "name") == 0)
5797 {
5798 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_scene->name);
5799 }
5800 else if (cgltf_json_strcmp(tokens+i, json_chunk, "nodes") == 0)
5801 {
5802 i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_node*), (void**)&out_scene->nodes, &out_scene->nodes_count);
5803 if (i < 0)
5804 {
5805 return i;
5806 }
5807
5808 for (cgltf_size k = 0; k < out_scene->nodes_count; ++k)
5809 {
5810 out_scene->nodes[k] = CGLTF_PTRINDEX(cgltf_node, cgltf_json_to_int(tokens + i, json_chunk));
5811 ++i;
5812 }
5813 }
5814 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
5815 {
5816 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_scene->extras);
5817 }
5818 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
5819 {
5820 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_scene->extensions_count, &out_scene->extensions);
5821 }
5822 else
5823 {
5824 i = cgltf_skip_json(tokens, i+1);
5825 }
5826
5827 if (i < 0)
5828 {
5829 return i;
5830 }
5831 }
5832
5833 return i;
5834}
5835
5836static int cgltf_parse_json_scenes(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
5837{
5838 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_scene), (void**)&out_data->scenes, &out_data->scenes_count);
5839 if (i < 0)
5840 {
5841 return i;
5842 }
5843
5844 for (cgltf_size j = 0; j < out_data->scenes_count; ++j)
5845 {
5846 i = cgltf_parse_json_scene(options, tokens, i, json_chunk, &out_data->scenes[j]);
5847 if (i < 0)
5848 {
5849 return i;
5850 }
5851 }
5852 return i;
5853}
5854
5855static int cgltf_parse_json_animation_sampler(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_animation_sampler* out_sampler)
5856{
5857 (void)options;
5858 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5859
5860 int size = tokens[i].size;
5861 ++i;
5862
5863 for (int j = 0; j < size; ++j)
5864 {
5865 CGLTF_CHECK_KEY(tokens[i]);
5866
5867 if (cgltf_json_strcmp(tokens+i, json_chunk, "input") == 0)
5868 {
5869 ++i;
5870 out_sampler->input = CGLTF_PTRINDEX(cgltf_accessor, cgltf_json_to_int(tokens + i, json_chunk));
5871 ++i;
5872 }
5873 else if (cgltf_json_strcmp(tokens+i, json_chunk, "output") == 0)
5874 {
5875 ++i;
5876 out_sampler->output = CGLTF_PTRINDEX(cgltf_accessor, cgltf_json_to_int(tokens + i, json_chunk));
5877 ++i;
5878 }
5879 else if (cgltf_json_strcmp(tokens+i, json_chunk, "interpolation") == 0)
5880 {
5881 ++i;
5882 if (cgltf_json_strcmp(tokens + i, json_chunk, "LINEAR") == 0)
5883 {
5884 out_sampler->interpolation = cgltf_interpolation_type_linear;
5885 }
5886 else if (cgltf_json_strcmp(tokens + i, json_chunk, "STEP") == 0)
5887 {
5888 out_sampler->interpolation = cgltf_interpolation_type_step;
5889 }
5890 else if (cgltf_json_strcmp(tokens + i, json_chunk, "CUBICSPLINE") == 0)
5891 {
5892 out_sampler->interpolation = cgltf_interpolation_type_cubic_spline;
5893 }
5894 ++i;
5895 }
5896 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
5897 {
5898 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sampler->extras);
5899 }
5900 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
5901 {
5902 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_sampler->extensions_count, &out_sampler->extensions);
5903 }
5904 else
5905 {
5906 i = cgltf_skip_json(tokens, i+1);
5907 }
5908
5909 if (i < 0)
5910 {
5911 return i;
5912 }
5913 }
5914
5915 return i;
5916}
5917
5918static int cgltf_parse_json_animation_channel(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_animation_channel* out_channel)
5919{
5920 (void)options;
5921 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5922
5923 int size = tokens[i].size;
5924 ++i;
5925
5926 for (int j = 0; j < size; ++j)
5927 {
5928 CGLTF_CHECK_KEY(tokens[i]);
5929
5930 if (cgltf_json_strcmp(tokens+i, json_chunk, "sampler") == 0)
5931 {
5932 ++i;
5933 out_channel->sampler = CGLTF_PTRINDEX(cgltf_animation_sampler, cgltf_json_to_int(tokens + i, json_chunk));
5934 ++i;
5935 }
5936 else if (cgltf_json_strcmp(tokens+i, json_chunk, "target") == 0)
5937 {
5938 ++i;
5939
5940 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
5941
5942 int target_size = tokens[i].size;
5943 ++i;
5944
5945 for (int k = 0; k < target_size; ++k)
5946 {
5947 CGLTF_CHECK_KEY(tokens[i]);
5948
5949 if (cgltf_json_strcmp(tokens+i, json_chunk, "node") == 0)
5950 {
5951 ++i;
5952 out_channel->target_node = CGLTF_PTRINDEX(cgltf_node, cgltf_json_to_int(tokens + i, json_chunk));
5953 ++i;
5954 }
5955 else if (cgltf_json_strcmp(tokens+i, json_chunk, "path") == 0)
5956 {
5957 ++i;
5958 if (cgltf_json_strcmp(tokens+i, json_chunk, "translation") == 0)
5959 {
5960 out_channel->target_path = cgltf_animation_path_type_translation;
5961 }
5962 else if (cgltf_json_strcmp(tokens+i, json_chunk, "rotation") == 0)
5963 {
5964 out_channel->target_path = cgltf_animation_path_type_rotation;
5965 }
5966 else if (cgltf_json_strcmp(tokens+i, json_chunk, "scale") == 0)
5967 {
5968 out_channel->target_path = cgltf_animation_path_type_scale;
5969 }
5970 else if (cgltf_json_strcmp(tokens+i, json_chunk, "weights") == 0)
5971 {
5972 out_channel->target_path = cgltf_animation_path_type_weights;
5973 }
5974 ++i;
5975 }
5976 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
5977 {
5978 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_channel->extras);
5979 }
5980 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
5981 {
5982 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_channel->extensions_count, &out_channel->extensions);
5983 }
5984 else
5985 {
5986 i = cgltf_skip_json(tokens, i+1);
5987 }
5988
5989 if (i < 0)
5990 {
5991 return i;
5992 }
5993 }
5994 }
5995 else
5996 {
5997 i = cgltf_skip_json(tokens, i+1);
5998 }
5999
6000 if (i < 0)
6001 {
6002 return i;
6003 }
6004 }
6005
6006 return i;
6007}
6008
6009static int cgltf_parse_json_animation(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_animation* out_animation)
6010{
6011 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
6012
6013 int size = tokens[i].size;
6014 ++i;
6015
6016 for (int j = 0; j < size; ++j)
6017 {
6018 CGLTF_CHECK_KEY(tokens[i]);
6019
6020 if (cgltf_json_strcmp(tokens+i, json_chunk, "name") == 0)
6021 {
6022 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_animation->name);
6023 }
6024 else if (cgltf_json_strcmp(tokens+i, json_chunk, "samplers") == 0)
6025 {
6026 i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_animation_sampler), (void**)&out_animation->samplers, &out_animation->samplers_count);
6027 if (i < 0)
6028 {
6029 return i;
6030 }
6031
6032 for (cgltf_size k = 0; k < out_animation->samplers_count; ++k)
6033 {
6034 i = cgltf_parse_json_animation_sampler(options, tokens, i, json_chunk, &out_animation->samplers[k]);
6035 if (i < 0)
6036 {
6037 return i;
6038 }
6039 }
6040 }
6041 else if (cgltf_json_strcmp(tokens+i, json_chunk, "channels") == 0)
6042 {
6043 i = cgltf_parse_json_array(options, tokens, i + 1, json_chunk, sizeof(cgltf_animation_channel), (void**)&out_animation->channels, &out_animation->channels_count);
6044 if (i < 0)
6045 {
6046 return i;
6047 }
6048
6049 for (cgltf_size k = 0; k < out_animation->channels_count; ++k)
6050 {
6051 i = cgltf_parse_json_animation_channel(options, tokens, i, json_chunk, &out_animation->channels[k]);
6052 if (i < 0)
6053 {
6054 return i;
6055 }
6056 }
6057 }
6058 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
6059 {
6060 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_animation->extras);
6061 }
6062 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
6063 {
6064 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_animation->extensions_count, &out_animation->extensions);
6065 }
6066 else
6067 {
6068 i = cgltf_skip_json(tokens, i+1);
6069 }
6070
6071 if (i < 0)
6072 {
6073 return i;
6074 }
6075 }
6076
6077 return i;
6078}
6079
6080static int cgltf_parse_json_animations(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
6081{
6082 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_animation), (void**)&out_data->animations, &out_data->animations_count);
6083 if (i < 0)
6084 {
6085 return i;
6086 }
6087
6088 for (cgltf_size j = 0; j < out_data->animations_count; ++j)
6089 {
6090 i = cgltf_parse_json_animation(options, tokens, i, json_chunk, &out_data->animations[j]);
6091 if (i < 0)
6092 {
6093 return i;
6094 }
6095 }
6096 return i;
6097}
6098
6099static int cgltf_parse_json_variant(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_material_variant* out_variant)
6100{
6101 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
6102
6103 int size = tokens[i].size;
6104 ++i;
6105
6106 for (int j = 0; j < size; ++j)
6107 {
6108 CGLTF_CHECK_KEY(tokens[i]);
6109
6110 if (cgltf_json_strcmp(tokens+i, json_chunk, "name") == 0)
6111 {
6112 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_variant->name);
6113 }
6114 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
6115 {
6116 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_variant->extras);
6117 }
6118 else
6119 {
6120 i = cgltf_skip_json(tokens, i+1);
6121 }
6122
6123 if (i < 0)
6124 {
6125 return i;
6126 }
6127 }
6128
6129 return i;
6130}
6131
6132static int cgltf_parse_json_variants(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
6133{
6134 i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(cgltf_material_variant), (void**)&out_data->variants, &out_data->variants_count);
6135 if (i < 0)
6136 {
6137 return i;
6138 }
6139
6140 for (cgltf_size j = 0; j < out_data->variants_count; ++j)
6141 {
6142 i = cgltf_parse_json_variant(options, tokens, i, json_chunk, &out_data->variants[j]);
6143 if (i < 0)
6144 {
6145 return i;
6146 }
6147 }
6148 return i;
6149}
6150
6151static int cgltf_parse_json_asset(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_asset* out_asset)
6152{
6153 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
6154
6155 int size = tokens[i].size;
6156 ++i;
6157
6158 for (int j = 0; j < size; ++j)
6159 {
6160 CGLTF_CHECK_KEY(tokens[i]);
6161
6162 if (cgltf_json_strcmp(tokens+i, json_chunk, "copyright") == 0)
6163 {
6164 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_asset->copyright);
6165 }
6166 else if (cgltf_json_strcmp(tokens+i, json_chunk, "generator") == 0)
6167 {
6168 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_asset->generator);
6169 }
6170 else if (cgltf_json_strcmp(tokens+i, json_chunk, "version") == 0)
6171 {
6172 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_asset->version);
6173 }
6174 else if (cgltf_json_strcmp(tokens+i, json_chunk, "minVersion") == 0)
6175 {
6176 i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_asset->min_version);
6177 }
6178 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
6179 {
6180 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_asset->extras);
6181 }
6182 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
6183 {
6184 i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_asset->extensions_count, &out_asset->extensions);
6185 }
6186 else
6187 {
6188 i = cgltf_skip_json(tokens, i+1);
6189 }
6190
6191 if (i < 0)
6192 {
6193 return i;
6194 }
6195 }
6196
6197 if (out_asset->version && CGLTF_ATOF(out_asset->version) < 2)
6198 {
6199 return CGLTF_ERROR_LEGACY;
6200 }
6201
6202 return i;
6203}
6204
6205cgltf_size cgltf_num_components(cgltf_type type) {
6206 switch (type)
6207 {
6208 case cgltf_type_vec2:
6209 return 2;
6210 case cgltf_type_vec3:
6211 return 3;
6212 case cgltf_type_vec4:
6213 return 4;
6214 case cgltf_type_mat2:
6215 return 4;
6216 case cgltf_type_mat3:
6217 return 9;
6218 case cgltf_type_mat4:
6219 return 16;
6220 case cgltf_type_invalid:
6221 case cgltf_type_scalar:
6222 default:
6223 return 1;
6224 }
6225}
6226
6227cgltf_size cgltf_component_size(cgltf_component_type component_type) {
6228 switch (component_type)
6229 {
6230 case cgltf_component_type_r_8:
6231 case cgltf_component_type_r_8u:
6232 return 1;
6233 case cgltf_component_type_r_16:
6234 case cgltf_component_type_r_16u:
6235 return 2;
6236 case cgltf_component_type_r_32u:
6237 case cgltf_component_type_r_32f:
6238 return 4;
6239 case cgltf_component_type_invalid:
6240 default:
6241 return 0;
6242 }
6243}
6244
6245cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type)
6246{
6247 cgltf_size component_size = cgltf_component_size(component_type);
6248 if (type == cgltf_type_mat2 && component_size == 1)
6249 {
6250 return 8 * component_size;
6251 }
6252 else if (type == cgltf_type_mat3 && (component_size == 1 || component_size == 2))
6253 {
6254 return 12 * component_size;
6255 }
6256 return component_size * cgltf_num_components(type);
6257}
6258
6259static int cgltf_fixup_pointers(cgltf_data* out_data);
6260
6261static int cgltf_parse_json_root(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_data* out_data)
6262{
6263 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
6264
6265 int size = tokens[i].size;
6266 ++i;
6267
6268 for (int j = 0; j < size; ++j)
6269 {
6270 CGLTF_CHECK_KEY(tokens[i]);
6271
6272 if (cgltf_json_strcmp(tokens + i, json_chunk, "asset") == 0)
6273 {
6274 i = cgltf_parse_json_asset(options, tokens, i + 1, json_chunk, &out_data->asset);
6275 }
6276 else if (cgltf_json_strcmp(tokens + i, json_chunk, "meshes") == 0)
6277 {
6278 i = cgltf_parse_json_meshes(options, tokens, i + 1, json_chunk, out_data);
6279 }
6280 else if (cgltf_json_strcmp(tokens + i, json_chunk, "accessors") == 0)
6281 {
6282 i = cgltf_parse_json_accessors(options, tokens, i + 1, json_chunk, out_data);
6283 }
6284 else if (cgltf_json_strcmp(tokens + i, json_chunk, "bufferViews") == 0)
6285 {
6286 i = cgltf_parse_json_buffer_views(options, tokens, i + 1, json_chunk, out_data);
6287 }
6288 else if (cgltf_json_strcmp(tokens + i, json_chunk, "buffers") == 0)
6289 {
6290 i = cgltf_parse_json_buffers(options, tokens, i + 1, json_chunk, out_data);
6291 }
6292 else if (cgltf_json_strcmp(tokens + i, json_chunk, "materials") == 0)
6293 {
6294 i = cgltf_parse_json_materials(options, tokens, i + 1, json_chunk, out_data);
6295 }
6296 else if (cgltf_json_strcmp(tokens + i, json_chunk, "images") == 0)
6297 {
6298 i = cgltf_parse_json_images(options, tokens, i + 1, json_chunk, out_data);
6299 }
6300 else if (cgltf_json_strcmp(tokens + i, json_chunk, "textures") == 0)
6301 {
6302 i = cgltf_parse_json_textures(options, tokens, i + 1, json_chunk, out_data);
6303 }
6304 else if (cgltf_json_strcmp(tokens + i, json_chunk, "samplers") == 0)
6305 {
6306 i = cgltf_parse_json_samplers(options, tokens, i + 1, json_chunk, out_data);
6307 }
6308 else if (cgltf_json_strcmp(tokens + i, json_chunk, "skins") == 0)
6309 {
6310 i = cgltf_parse_json_skins(options, tokens, i + 1, json_chunk, out_data);
6311 }
6312 else if (cgltf_json_strcmp(tokens + i, json_chunk, "cameras") == 0)
6313 {
6314 i = cgltf_parse_json_cameras(options, tokens, i + 1, json_chunk, out_data);
6315 }
6316 else if (cgltf_json_strcmp(tokens + i, json_chunk, "nodes") == 0)
6317 {
6318 i = cgltf_parse_json_nodes(options, tokens, i + 1, json_chunk, out_data);
6319 }
6320 else if (cgltf_json_strcmp(tokens + i, json_chunk, "scenes") == 0)
6321 {
6322 i = cgltf_parse_json_scenes(options, tokens, i + 1, json_chunk, out_data);
6323 }
6324 else if (cgltf_json_strcmp(tokens + i, json_chunk, "scene") == 0)
6325 {
6326 ++i;
6327 out_data->scene = CGLTF_PTRINDEX(cgltf_scene, cgltf_json_to_int(tokens + i, json_chunk));
6328 ++i;
6329 }
6330 else if (cgltf_json_strcmp(tokens + i, json_chunk, "animations") == 0)
6331 {
6332 i = cgltf_parse_json_animations(options, tokens, i + 1, json_chunk, out_data);
6333 }
6334 else if (cgltf_json_strcmp(tokens+i, json_chunk, "extras") == 0)
6335 {
6336 i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_data->extras);
6337 }
6338 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
6339 {
6340 ++i;
6341
6342 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
6343 if(out_data->data_extensions)
6344 {
6345 return CGLTF_ERROR_JSON;
6346 }
6347
6348 int extensions_size = tokens[i].size;
6349 out_data->data_extensions_count = 0;
6350 out_data->data_extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size);
6351
6352 if (!out_data->data_extensions)
6353 {
6354 return CGLTF_ERROR_NOMEM;
6355 }
6356
6357 ++i;
6358
6359 for (int k = 0; k < extensions_size; ++k)
6360 {
6361 CGLTF_CHECK_KEY(tokens[i]);
6362
6363 if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_lights_punctual") == 0)
6364 {
6365 ++i;
6366
6367 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
6368
6369 int data_size = tokens[i].size;
6370 ++i;
6371
6372 for (int m = 0; m < data_size; ++m)
6373 {
6374 CGLTF_CHECK_KEY(tokens[i]);
6375
6376 if (cgltf_json_strcmp(tokens + i, json_chunk, "lights") == 0)
6377 {
6378 i = cgltf_parse_json_lights(options, tokens, i + 1, json_chunk, out_data);
6379 }
6380 else
6381 {
6382 i = cgltf_skip_json(tokens, i + 1);
6383 }
6384
6385 if (i < 0)
6386 {
6387 return i;
6388 }
6389 }
6390 }
6391 else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_variants") == 0)
6392 {
6393 ++i;
6394
6395 CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
6396
6397 int data_size = tokens[i].size;
6398 ++i;
6399
6400 for (int m = 0; m < data_size; ++m)
6401 {
6402 CGLTF_CHECK_KEY(tokens[i]);
6403
6404 if (cgltf_json_strcmp(tokens + i, json_chunk, "variants") == 0)
6405 {
6406 i = cgltf_parse_json_variants(options, tokens, i + 1, json_chunk, out_data);
6407 }
6408 else
6409 {
6410 i = cgltf_skip_json(tokens, i + 1);
6411 }
6412
6413 if (i < 0)
6414 {
6415 return i;
6416 }
6417 }
6418 }
6419 else
6420 {
6421 i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_data->data_extensions[out_data->data_extensions_count++]));
6422 }
6423
6424 if (i < 0)
6425 {
6426 return i;
6427 }
6428 }
6429 }
6430 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensionsUsed") == 0)
6431 {
6432 i = cgltf_parse_json_string_array(options, tokens, i + 1, json_chunk, &out_data->extensions_used, &out_data->extensions_used_count);
6433 }
6434 else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensionsRequired") == 0)
6435 {
6436 i = cgltf_parse_json_string_array(options, tokens, i + 1, json_chunk, &out_data->extensions_required, &out_data->extensions_required_count);
6437 }
6438 else
6439 {
6440 i = cgltf_skip_json(tokens, i + 1);
6441 }
6442
6443 if (i < 0)
6444 {
6445 return i;
6446 }
6447 }
6448
6449 return i;
6450}
6451
6452cgltf_result cgltf_parse_json(cgltf_options* options, const uint8_t* json_chunk, cgltf_size size, cgltf_data** out_data)
6453{
6454 jsmn_parser parser = { 0, 0, 0 };
6455
6456 if (options->json_token_count == 0)
6457 {
6458 int token_count = jsmn_parse(&parser, (const char*)json_chunk, size, NULL, 0);
6459
6460 if (token_count <= 0)
6461 {
6462 return cgltf_result_invalid_json;
6463 }
6464
6465 options->json_token_count = token_count;
6466 }
6467
6468 jsmntok_t* tokens = (jsmntok_t*)options->memory.alloc_func(options->memory.user_data, sizeof(jsmntok_t) * (options->json_token_count + 1));
6469
6470 if (!tokens)
6471 {
6472 return cgltf_result_out_of_memory;
6473 }
6474
6475 jsmn_init(&parser);
6476
6477 int token_count = jsmn_parse(&parser, (const char*)json_chunk, size, tokens, options->json_token_count);
6478
6479 if (token_count <= 0)
6480 {
6481 options->memory.free_func(options->memory.user_data, tokens);
6482 return cgltf_result_invalid_json;
6483 }
6484
6485 // this makes sure that we always have an UNDEFINED token at the end of the stream
6486 // for invalid JSON inputs this makes sure we don't perform out of bound reads of token data
6487 tokens[token_count].type = JSMN_UNDEFINED;
6488
6489 cgltf_data* data = (cgltf_data*)options->memory.alloc_func(options->memory.user_data, sizeof(cgltf_data));
6490
6491 if (!data)
6492 {
6493 options->memory.free_func(options->memory.user_data, tokens);
6494 return cgltf_result_out_of_memory;
6495 }
6496
6497 memset(data, 0, sizeof(cgltf_data));
6498 data->memory = options->memory;
6499 data->file = options->file;
6500
6501 int i = cgltf_parse_json_root(options, tokens, 0, json_chunk, data);
6502
6503 options->memory.free_func(options->memory.user_data, tokens);
6504
6505 if (i < 0)
6506 {
6507 cgltf_free(data);
6508
6509 switch (i)
6510 {
6511 case CGLTF_ERROR_NOMEM: return cgltf_result_out_of_memory;
6512 case CGLTF_ERROR_LEGACY: return cgltf_result_legacy_gltf;
6513 default: return cgltf_result_invalid_gltf;
6514 }
6515 }
6516
6517 if (cgltf_fixup_pointers(data) < 0)
6518 {
6519 cgltf_free(data);
6520 return cgltf_result_invalid_gltf;
6521 }
6522
6523 data->json = (const char*)json_chunk;
6524 data->json_size = size;
6525
6526 *out_data = data;
6527
6528 return cgltf_result_success;
6529}
6530
6531static int cgltf_fixup_pointers(cgltf_data* data)
6532{
6533 for (cgltf_size i = 0; i < data->meshes_count; ++i)
6534 {
6535 for (cgltf_size j = 0; j < data->meshes[i].primitives_count; ++j)
6536 {
6537 CGLTF_PTRFIXUP(data->meshes[i].primitives[j].indices, data->accessors, data->accessors_count);
6538 CGLTF_PTRFIXUP(data->meshes[i].primitives[j].material, data->materials, data->materials_count);
6539
6540 for (cgltf_size k = 0; k < data->meshes[i].primitives[j].attributes_count; ++k)
6541 {
6542 CGLTF_PTRFIXUP_REQ(data->meshes[i].primitives[j].attributes[k].data, data->accessors, data->accessors_count);
6543 }
6544
6545 for (cgltf_size k = 0; k < data->meshes[i].primitives[j].targets_count; ++k)
6546 {
6547 for (cgltf_size m = 0; m < data->meshes[i].primitives[j].targets[k].attributes_count; ++m)
6548 {
6549 CGLTF_PTRFIXUP_REQ(data->meshes[i].primitives[j].targets[k].attributes[m].data, data->accessors, data->accessors_count);
6550 }
6551 }
6552
6553 if (data->meshes[i].primitives[j].has_draco_mesh_compression)
6554 {
6555 CGLTF_PTRFIXUP_REQ(data->meshes[i].primitives[j].draco_mesh_compression.buffer_view, data->buffer_views, data->buffer_views_count);
6556 for (cgltf_size m = 0; m < data->meshes[i].primitives[j].draco_mesh_compression.attributes_count; ++m)
6557 {
6558 CGLTF_PTRFIXUP_REQ(data->meshes[i].primitives[j].draco_mesh_compression.attributes[m].data, data->accessors, data->accessors_count);
6559 }
6560 }
6561
6562 for (cgltf_size k = 0; k < data->meshes[i].primitives[j].mappings_count; ++k)
6563 {
6564 CGLTF_PTRFIXUP_REQ(data->meshes[i].primitives[j].mappings[k].material, data->materials, data->materials_count);
6565 }
6566 }
6567 }
6568
6569 for (cgltf_size i = 0; i < data->accessors_count; ++i)
6570 {
6571 CGLTF_PTRFIXUP(data->accessors[i].buffer_view, data->buffer_views, data->buffer_views_count);
6572
6573 if (data->accessors[i].is_sparse)
6574 {
6575 CGLTF_PTRFIXUP_REQ(data->accessors[i].sparse.indices_buffer_view, data->buffer_views, data->buffer_views_count);
6576 CGLTF_PTRFIXUP_REQ(data->accessors[i].sparse.values_buffer_view, data->buffer_views, data->buffer_views_count);
6577 }
6578
6579 if (data->accessors[i].buffer_view)
6580 {
6581 data->accessors[i].stride = data->accessors[i].buffer_view->stride;
6582 }
6583
6584 if (data->accessors[i].stride == 0)
6585 {
6586 data->accessors[i].stride = cgltf_calc_size(data->accessors[i].type, data->accessors[i].component_type);
6587 }
6588 }
6589
6590 for (cgltf_size i = 0; i < data->textures_count; ++i)
6591 {
6592 CGLTF_PTRFIXUP(data->textures[i].image, data->images, data->images_count);
6593 CGLTF_PTRFIXUP(data->textures[i].basisu_image, data->images, data->images_count);
6594 CGLTF_PTRFIXUP(data->textures[i].webp_image, data->images, data->images_count);
6595 CGLTF_PTRFIXUP(data->textures[i].sampler, data->samplers, data->samplers_count);
6596 }
6597
6598 for (cgltf_size i = 0; i < data->images_count; ++i)
6599 {
6600 CGLTF_PTRFIXUP(data->images[i].buffer_view, data->buffer_views, data->buffer_views_count);
6601 }
6602
6603 for (cgltf_size i = 0; i < data->materials_count; ++i)
6604 {
6605 CGLTF_PTRFIXUP(data->materials[i].normal_texture.texture, data->textures, data->textures_count);
6606 CGLTF_PTRFIXUP(data->materials[i].emissive_texture.texture, data->textures, data->textures_count);
6607 CGLTF_PTRFIXUP(data->materials[i].occlusion_texture.texture, data->textures, data->textures_count);
6608
6609 CGLTF_PTRFIXUP(data->materials[i].pbr_metallic_roughness.base_color_texture.texture, data->textures, data->textures_count);
6610 CGLTF_PTRFIXUP(data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture, data->textures, data->textures_count);
6611
6612 CGLTF_PTRFIXUP(data->materials[i].pbr_specular_glossiness.diffuse_texture.texture, data->textures, data->textures_count);
6613 CGLTF_PTRFIXUP(data->materials[i].pbr_specular_glossiness.specular_glossiness_texture.texture, data->textures, data->textures_count);
6614
6615 CGLTF_PTRFIXUP(data->materials[i].clearcoat.clearcoat_texture.texture, data->textures, data->textures_count);
6616 CGLTF_PTRFIXUP(data->materials[i].clearcoat.clearcoat_roughness_texture.texture, data->textures, data->textures_count);
6617 CGLTF_PTRFIXUP(data->materials[i].clearcoat.clearcoat_normal_texture.texture, data->textures, data->textures_count);
6618
6619 CGLTF_PTRFIXUP(data->materials[i].specular.specular_texture.texture, data->textures, data->textures_count);
6620 CGLTF_PTRFIXUP(data->materials[i].specular.specular_color_texture.texture, data->textures, data->textures_count);
6621
6622 CGLTF_PTRFIXUP(data->materials[i].transmission.transmission_texture.texture, data->textures, data->textures_count);
6623
6624 CGLTF_PTRFIXUP(data->materials[i].volume.thickness_texture.texture, data->textures, data->textures_count);
6625
6626 CGLTF_PTRFIXUP(data->materials[i].sheen.sheen_color_texture.texture, data->textures, data->textures_count);
6627 CGLTF_PTRFIXUP(data->materials[i].sheen.sheen_roughness_texture.texture, data->textures, data->textures_count);
6628
6629 CGLTF_PTRFIXUP(data->materials[i].iridescence.iridescence_texture.texture, data->textures, data->textures_count);
6630 CGLTF_PTRFIXUP(data->materials[i].iridescence.iridescence_thickness_texture.texture, data->textures, data->textures_count);
6631
6632 CGLTF_PTRFIXUP(data->materials[i].anisotropy.anisotropy_texture.texture, data->textures, data->textures_count);
6633 }
6634
6635 for (cgltf_size i = 0; i < data->buffer_views_count; ++i)
6636 {
6637 CGLTF_PTRFIXUP_REQ(data->buffer_views[i].buffer, data->buffers, data->buffers_count);
6638
6639 if (data->buffer_views[i].has_meshopt_compression)
6640 {
6641 CGLTF_PTRFIXUP_REQ(data->buffer_views[i].meshopt_compression.buffer, data->buffers, data->buffers_count);
6642 }
6643 }
6644
6645 for (cgltf_size i = 0; i < data->skins_count; ++i)
6646 {
6647 for (cgltf_size j = 0; j < data->skins[i].joints_count; ++j)
6648 {
6649 CGLTF_PTRFIXUP_REQ(data->skins[i].joints[j], data->nodes, data->nodes_count);
6650 }
6651
6652 CGLTF_PTRFIXUP(data->skins[i].skeleton, data->nodes, data->nodes_count);
6653 CGLTF_PTRFIXUP(data->skins[i].inverse_bind_matrices, data->accessors, data->accessors_count);
6654 }
6655
6656 for (cgltf_size i = 0; i < data->nodes_count; ++i)
6657 {
6658 for (cgltf_size j = 0; j < data->nodes[i].children_count; ++j)
6659 {
6660 CGLTF_PTRFIXUP_REQ(data->nodes[i].children[j], data->nodes, data->nodes_count);
6661
6662 if (data->nodes[i].children[j]->parent)
6663 {
6664 return CGLTF_ERROR_JSON;
6665 }
6666
6667 data->nodes[i].children[j]->parent = &data->nodes[i];
6668 }
6669
6670 CGLTF_PTRFIXUP(data->nodes[i].mesh, data->meshes, data->meshes_count);
6671 CGLTF_PTRFIXUP(data->nodes[i].skin, data->skins, data->skins_count);
6672 CGLTF_PTRFIXUP(data->nodes[i].camera, data->cameras, data->cameras_count);
6673 CGLTF_PTRFIXUP(data->nodes[i].light, data->lights, data->lights_count);
6674
6675 if (data->nodes[i].has_mesh_gpu_instancing)
6676 {
6677 for (cgltf_size m = 0; m < data->nodes[i].mesh_gpu_instancing.attributes_count; ++m)
6678 {
6679 CGLTF_PTRFIXUP_REQ(data->nodes[i].mesh_gpu_instancing.attributes[m].data, data->accessors, data->accessors_count);
6680 }
6681 }
6682 }
6683
6684 for (cgltf_size i = 0; i < data->scenes_count; ++i)
6685 {
6686 for (cgltf_size j = 0; j < data->scenes[i].nodes_count; ++j)
6687 {
6688 CGLTF_PTRFIXUP_REQ(data->scenes[i].nodes[j], data->nodes, data->nodes_count);
6689
6690 if (data->scenes[i].nodes[j]->parent)
6691 {
6692 return CGLTF_ERROR_JSON;
6693 }
6694 }
6695 }
6696
6697 CGLTF_PTRFIXUP(data->scene, data->scenes, data->scenes_count);
6698
6699 for (cgltf_size i = 0; i < data->animations_count; ++i)
6700 {
6701 for (cgltf_size j = 0; j < data->animations[i].samplers_count; ++j)
6702 {
6703 CGLTF_PTRFIXUP_REQ(data->animations[i].samplers[j].input, data->accessors, data->accessors_count);
6704 CGLTF_PTRFIXUP_REQ(data->animations[i].samplers[j].output, data->accessors, data->accessors_count);
6705 }
6706
6707 for (cgltf_size j = 0; j < data->animations[i].channels_count; ++j)
6708 {
6709 CGLTF_PTRFIXUP_REQ(data->animations[i].channels[j].sampler, data->animations[i].samplers, data->animations[i].samplers_count);
6710 CGLTF_PTRFIXUP(data->animations[i].channels[j].target_node, data->nodes, data->nodes_count);
6711 }
6712 }
6713
6714 return 0;
6715}
6716
6717/*
6718 * -- jsmn.c start --
6719 * Source: https://github.com/zserge/jsmn
6720 * License: MIT
6721 *
6722 * Copyright (c) 2010 Serge A. Zaitsev
6723
6724 * Permission is hereby granted, free of charge, to any person obtaining a copy
6725 * of this software and associated documentation files (the "Software"), to deal
6726 * in the Software without restriction, including without limitation the rights
6727 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
6728 * copies of the Software, and to permit persons to whom the Software is
6729 * furnished to do so, subject to the following conditions:
6730
6731 * The above copyright notice and this permission notice shall be included in
6732 * all copies or substantial portions of the Software.
6733
6734 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6735 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6736 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6737 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6738 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
6739 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
6740 * THE SOFTWARE.
6741 */
6742
6743/**
6744 * Allocates a fresh unused token from the token pull.
6745 */
6746static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
6747 jsmntok_t *tokens, size_t num_tokens) {
6748 jsmntok_t *tok;
6749 if (parser->toknext >= num_tokens) {
6750 return NULL;
6751 }
6752 tok = &tokens[parser->toknext++];
6753 tok->start = tok->end = -1;
6754 tok->size = 0;
6755#ifdef JSMN_PARENT_LINKS
6756 tok->parent = -1;
6757#endif
6758 return tok;
6759}
6760
6761/**
6762 * Fills token type and boundaries.
6763 */
6764static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
6765 ptrdiff_t start, ptrdiff_t end) {
6766 token->type = type;
6767 token->start = start;
6768 token->end = end;
6769 token->size = 0;
6770}
6771
6772/**
6773 * Fills next available token with JSON primitive.
6774 */
6775static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
6776 size_t len, jsmntok_t *tokens, size_t num_tokens) {
6777 jsmntok_t *token;
6778 ptrdiff_t start;
6779
6780 start = parser->pos;
6781
6782 for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
6783 switch (js[parser->pos]) {
6784#ifndef JSMN_STRICT
6785 /* In strict mode primitive must be followed by "," or "}" or "]" */
6786 case ':':
6787#endif
6788 case '\t' : case '\r' : case '\n' : case ' ' :
6789 case ',' : case ']' : case '}' :
6790 goto found;
6791 }
6792 if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
6793 parser->pos = start;
6794 return JSMN_ERROR_INVAL;
6795 }
6796 }
6797#ifdef JSMN_STRICT
6798 /* In strict mode primitive must be followed by a comma/object/array */
6799 parser->pos = start;
6800 return JSMN_ERROR_PART;
6801#endif
6802
6803found:
6804 if (tokens == NULL) {
6805 parser->pos--;
6806 return 0;
6807 }
6808 token = jsmn_alloc_token(parser, tokens, num_tokens);
6809 if (token == NULL) {
6810 parser->pos = start;
6811 return JSMN_ERROR_NOMEM;
6812 }
6813 jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
6814#ifdef JSMN_PARENT_LINKS
6815 token->parent = parser->toksuper;
6816#endif
6817 parser->pos--;
6818 return 0;
6819}
6820
6821/**
6822 * Fills next token with JSON string.
6823 */
6824static int jsmn_parse_string(jsmn_parser *parser, const char *js,
6825 size_t len, jsmntok_t *tokens, size_t num_tokens) {
6826 jsmntok_t *token;
6827
6828 ptrdiff_t start = parser->pos;
6829
6830 parser->pos++;
6831
6832 /* Skip starting quote */
6833 for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
6834 char c = js[parser->pos];
6835
6836 /* Quote: end of string */
6837 if (c == '\"') {
6838 if (tokens == NULL) {
6839 return 0;
6840 }
6841 token = jsmn_alloc_token(parser, tokens, num_tokens);
6842 if (token == NULL) {
6843 parser->pos = start;
6844 return JSMN_ERROR_NOMEM;
6845 }
6846 jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
6847#ifdef JSMN_PARENT_LINKS
6848 token->parent = parser->toksuper;
6849#endif
6850 return 0;
6851 }
6852
6853 /* Backslash: Quoted symbol expected */
6854 if (c == '\\' && parser->pos + 1 < len) {
6855 int i;
6856 parser->pos++;
6857 switch (js[parser->pos]) {
6858 /* Allowed escaped symbols */
6859 case '\"': case '/' : case '\\' : case 'b' :
6860 case 'f' : case 'r' : case 'n' : case 't' :
6861 break;
6862 /* Allows escaped symbol \uXXXX */
6863 case 'u':
6864 parser->pos++;
6865 for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
6866 /* If it isn't a hex character we have an error */
6867 if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
6868 (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
6869 (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
6870 parser->pos = start;
6871 return JSMN_ERROR_INVAL;
6872 }
6873 parser->pos++;
6874 }
6875 parser->pos--;
6876 break;
6877 /* Unexpected symbol */
6878 default:
6879 parser->pos = start;
6880 return JSMN_ERROR_INVAL;
6881 }
6882 }
6883 }
6884 parser->pos = start;
6885 return JSMN_ERROR_PART;
6886}
6887
6888/**
6889 * Parse JSON string and fill tokens.
6890 */
6891static int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
6892 jsmntok_t *tokens, size_t num_tokens) {
6893 int r;
6894 int i;
6895 jsmntok_t *token;
6896 int count = parser->toknext;
6897
6898 for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
6899 char c;
6900 jsmntype_t type;
6901
6902 c = js[parser->pos];
6903 switch (c) {
6904 case '{': case '[':
6905 count++;
6906 if (tokens == NULL) {
6907 break;
6908 }
6909 token = jsmn_alloc_token(parser, tokens, num_tokens);
6910 if (token == NULL)
6911 return JSMN_ERROR_NOMEM;
6912 if (parser->toksuper != -1) {
6913 tokens[parser->toksuper].size++;
6914#ifdef JSMN_PARENT_LINKS
6915 token->parent = parser->toksuper;
6916#endif
6917 }
6918 token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
6919 token->start = parser->pos;
6920 parser->toksuper = parser->toknext - 1;
6921 break;
6922 case '}': case ']':
6923 if (tokens == NULL)
6924 break;
6925 type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
6926#ifdef JSMN_PARENT_LINKS
6927 if (parser->toknext < 1) {
6928 return JSMN_ERROR_INVAL;
6929 }
6930 token = &tokens[parser->toknext - 1];
6931 for (;;) {
6932 if (token->start != -1 && token->end == -1) {
6933 if (token->type != type) {
6934 return JSMN_ERROR_INVAL;
6935 }
6936 token->end = parser->pos + 1;
6937 parser->toksuper = token->parent;
6938 break;
6939 }
6940 if (token->parent == -1) {
6941 if(token->type != type || parser->toksuper == -1) {
6942 return JSMN_ERROR_INVAL;
6943 }
6944 break;
6945 }
6946 token = &tokens[token->parent];
6947 }
6948#else
6949 for (i = parser->toknext - 1; i >= 0; i--) {
6950 token = &tokens[i];
6951 if (token->start != -1 && token->end == -1) {
6952 if (token->type != type) {
6953 return JSMN_ERROR_INVAL;
6954 }
6955 parser->toksuper = -1;
6956 token->end = parser->pos + 1;
6957 break;
6958 }
6959 }
6960 /* Error if unmatched closing bracket */
6961 if (i == -1) return JSMN_ERROR_INVAL;
6962 for (; i >= 0; i--) {
6963 token = &tokens[i];
6964 if (token->start != -1 && token->end == -1) {
6965 parser->toksuper = i;
6966 break;
6967 }
6968 }
6969#endif
6970 break;
6971 case '\"':
6972 r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
6973 if (r < 0) return r;
6974 count++;
6975 if (parser->toksuper != -1 && tokens != NULL)
6976 tokens[parser->toksuper].size++;
6977 break;
6978 case '\t' : case '\r' : case '\n' : case ' ':
6979 break;
6980 case ':':
6981 parser->toksuper = parser->toknext - 1;
6982 break;
6983 case ',':
6984 if (tokens != NULL && parser->toksuper != -1 &&
6985 tokens[parser->toksuper].type != JSMN_ARRAY &&
6986 tokens[parser->toksuper].type != JSMN_OBJECT) {
6987#ifdef JSMN_PARENT_LINKS
6988 parser->toksuper = tokens[parser->toksuper].parent;
6989#else
6990 for (i = parser->toknext - 1; i >= 0; i--) {
6991 if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
6992 if (tokens[i].start != -1 && tokens[i].end == -1) {
6993 parser->toksuper = i;
6994 break;
6995 }
6996 }
6997 }
6998#endif
6999 }
7000 break;
7001#ifdef JSMN_STRICT
7002 /* In strict mode primitives are: numbers and booleans */
7003 case '-': case '0': case '1' : case '2': case '3' : case '4':
7004 case '5': case '6': case '7' : case '8': case '9':
7005 case 't': case 'f': case 'n' :
7006 /* And they must not be keys of the object */
7007 if (tokens != NULL && parser->toksuper != -1) {
7008 jsmntok_t *t = &tokens[parser->toksuper];
7009 if (t->type == JSMN_OBJECT ||
7010 (t->type == JSMN_STRING && t->size != 0)) {
7011 return JSMN_ERROR_INVAL;
7012 }
7013 }
7014#else
7015 /* In non-strict mode every unquoted value is a primitive */
7016 default:
7017#endif
7018 r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
7019 if (r < 0) return r;
7020 count++;
7021 if (parser->toksuper != -1 && tokens != NULL)
7022 tokens[parser->toksuper].size++;
7023 break;
7024
7025#ifdef JSMN_STRICT
7026 /* Unexpected char in strict mode */
7027 default:
7028 return JSMN_ERROR_INVAL;
7029#endif
7030 }
7031 }
7032
7033 if (tokens != NULL) {
7034 for (i = parser->toknext - 1; i >= 0; i--) {
7035 /* Unmatched opened object or array */
7036 if (tokens[i].start != -1 && tokens[i].end == -1) {
7037 return JSMN_ERROR_PART;
7038 }
7039 }
7040 }
7041
7042 return count;
7043}
7044
7045/**
7046 * Creates a new parser based over a given buffer with an array of tokens
7047 * available.
7048 */
7049static void jsmn_init(jsmn_parser *parser) {
7050 parser->pos = 0;
7051 parser->toknext = 0;
7052 parser->toksuper = -1;
7053}
7054/*
7055 * -- jsmn.c end --
7056 */
7057
7058#endif /* #ifdef CGLTF_IMPLEMENTATION */
7059
7060/* cgltf is distributed under MIT license:
7061 *
7062 * Copyright (c) 2018-2021 Johannes Kuhlmann
7063
7064 * Permission is hereby granted, free of charge, to any person obtaining a copy
7065 * of this software and associated documentation files (the "Software"), to deal
7066 * in the Software without restriction, including without limitation the rights
7067 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7068 * copies of the Software, and to permit persons to whom the Software is
7069 * furnished to do so, subject to the following conditions:
7070
7071 * The above copyright notice and this permission notice shall be included in all
7072 * copies or substantial portions of the Software.
7073
7074 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
7075 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
7076 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
7077 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
7078 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7079 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
7080 * SOFTWARE.
7081 */
diff --git a/raylib/src/external/dirent.h b/raylib/src/external/dirent.h
new file mode 100644
index 0000000..c611376
--- /dev/null
+++ b/raylib/src/external/dirent.h
@@ -0,0 +1,183 @@
1/****************************************************************************
2
3 Declaration of POSIX directory browsing functions and types for Win32.
4
5 Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com)
6 History: Created March 1997. Updated June 2003.
7 Reviewed by Ramon Santamaria for raylib on January 2020.
8
9 Copyright Kevlin Henney, 1997, 2003. All rights reserved.
10
11 Permission to use, copy, modify, and distribute this software and its
12 documentation for any purpose is hereby granted without fee, provided
13 that this copyright and permissions notice appear in all copies and
14 derivatives.
15
16 This software is supplied "as is" without express or implied warranty.
17
18 But that said, if there are any problems please get in touch.
19
20****************************************************************************/
21
22#ifndef DIRENT_H
23#define DIRENT_H
24
25// Allow custom memory allocators
26#ifndef DIRENT_MALLOC
27 #define DIRENT_MALLOC(sz) malloc(sz)
28#endif
29#ifndef DIRENT_FREE
30 #define DIRENT_FREE(p) free(p)
31#endif
32
33//----------------------------------------------------------------------------------
34// Types and Structures Definition
35//----------------------------------------------------------------------------------
36
37// Fordward declaration of DIR, implementation below
38typedef struct DIR DIR;
39
40struct dirent {
41 char *d_name;
42};
43
44#ifdef __cplusplus
45extern "C" {
46#endif
47
48//------------------------------------------------------------------------------------
49// Functions Declaration
50//------------------------------------------------------------------------------------
51DIR *opendir(const char *name);
52int closedir(DIR *dir);
53struct dirent *readdir(DIR *dir);
54void rewinddir(DIR *dir);
55
56#ifdef __cplusplus
57}
58#endif
59
60#endif // DIRENT_H
61
62/****************************************************************************
63
64 Implementation of POSIX directory browsing functions and types for Win32.
65
66 Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com)
67 History: Created March 1997. Updated June 2003.
68 Reviewed by Ramon Santamaria for raylib on January 2020.
69
70 Copyright Kevlin Henney, 1997, 2003. All rights reserved.
71
72 Permission to use, copy, modify, and distribute this software and its
73 documentation for any purpose is hereby granted without fee, provided
74 that this copyright and permissions notice appear in all copies and
75 derivatives.
76
77 This software is supplied "as is" without express or implied warranty.
78
79 But that said, if there are any problems please get in touch.
80
81****************************************************************************/
82
83#include <io.h> // _findfirst and _findnext set errno iff they return -1
84#include <stdlib.h>
85#include <string.h>
86#include <errno.h>
87
88//----------------------------------------------------------------------------------
89// Types and Structures Definition
90//----------------------------------------------------------------------------------
91typedef ptrdiff_t handle_type; // C99's intptr_t not sufficiently portable
92
93struct DIR {
94 handle_type handle; // -1 for failed rewind
95 struct _finddata_t info;
96 struct dirent result; // d_name null iff first time
97 char *name; // null-terminated char string
98};
99
100DIR *opendir(const char *name)
101{
102 DIR *dir = 0;
103
104 if (name && name[0])
105 {
106 size_t base_length = strlen(name);
107
108 // Search pattern must end with suitable wildcard
109 const char *all = strchr("/\\", name[base_length - 1]) ? "*" : "/*";
110
111 if ((dir = (DIR *)DIRENT_MALLOC(sizeof *dir)) != 0 &&
112 (dir->name = (char *)DIRENT_MALLOC(base_length + strlen(all) + 1)) != 0)
113 {
114 strcat(strcpy(dir->name, name), all);
115
116 if ((dir->handle = (handle_type) _findfirst(dir->name, &dir->info)) != -1)
117 {
118 dir->result.d_name = 0;
119 }
120 else // rollback
121 {
122 DIRENT_FREE(dir->name);
123 DIRENT_FREE(dir);
124 dir = 0;
125 }
126 }
127 else // rollback
128 {
129 DIRENT_FREE(dir);
130 dir = 0;
131 errno = ENOMEM;
132 }
133 }
134 else errno = EINVAL;
135
136 return dir;
137}
138
139int closedir(DIR *dir)
140{
141 int result = -1;
142
143 if (dir)
144 {
145 if (dir->handle != -1) result = _findclose(dir->handle);
146
147 DIRENT_FREE(dir->name);
148 DIRENT_FREE(dir);
149 }
150
151 // NOTE: All errors ampped to EBADF
152 if (result == -1) errno = EBADF;
153
154 return result;
155}
156
157struct dirent *readdir(DIR *dir)
158{
159 struct dirent *result = 0;
160
161 if (dir && dir->handle != -1)
162 {
163 if (!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1)
164 {
165 result = &dir->result;
166 result->d_name = dir->info.name;
167 }
168 }
169 else errno = EBADF;
170
171 return result;
172}
173
174void rewinddir(DIR *dir)
175{
176 if (dir && dir->handle != -1)
177 {
178 _findclose(dir->handle);
179 dir->handle = (handle_type) _findfirst(dir->name, &dir->info);
180 dir->result.d_name = 0;
181 }
182 else errno = EBADF;
183}
diff --git a/raylib/src/external/dr_flac.h b/raylib/src/external/dr_flac.h
new file mode 100644
index 0000000..14324cf
--- /dev/null
+++ b/raylib/src/external/dr_flac.h
@@ -0,0 +1,12536 @@
1/*
2FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
3dr_flac - v0.12.42 - 2023-11-02
4
5David Reid - mackron@gmail.com
6
7GitHub: https://github.com/mackron/dr_libs
8*/
9
10/*
11RELEASE NOTES - v0.12.0
12=======================
13Version 0.12.0 has breaking API changes including changes to the existing API and the removal of deprecated APIs.
14
15
16Improved Client-Defined Memory Allocation
17-----------------------------------------
18The main change with this release is the addition of a more flexible way of implementing custom memory allocation routines. The
19existing system of DRFLAC_MALLOC, DRFLAC_REALLOC and DRFLAC_FREE are still in place and will be used by default when no custom
20allocation callbacks are specified.
21
22To use the new system, you pass in a pointer to a drflac_allocation_callbacks object to drflac_open() and family, like this:
23
24 void* my_malloc(size_t sz, void* pUserData)
25 {
26 return malloc(sz);
27 }
28 void* my_realloc(void* p, size_t sz, void* pUserData)
29 {
30 return realloc(p, sz);
31 }
32 void my_free(void* p, void* pUserData)
33 {
34 free(p);
35 }
36
37 ...
38
39 drflac_allocation_callbacks allocationCallbacks;
40 allocationCallbacks.pUserData = &myData;
41 allocationCallbacks.onMalloc = my_malloc;
42 allocationCallbacks.onRealloc = my_realloc;
43 allocationCallbacks.onFree = my_free;
44 drflac* pFlac = drflac_open_file("my_file.flac", &allocationCallbacks);
45
46The advantage of this new system is that it allows you to specify user data which will be passed in to the allocation routines.
47
48Passing in null for the allocation callbacks object will cause dr_flac to use defaults which is the same as DRFLAC_MALLOC,
49DRFLAC_REALLOC and DRFLAC_FREE and the equivalent of how it worked in previous versions.
50
51Every API that opens a drflac object now takes this extra parameter. These include the following:
52
53 drflac_open()
54 drflac_open_relaxed()
55 drflac_open_with_metadata()
56 drflac_open_with_metadata_relaxed()
57 drflac_open_file()
58 drflac_open_file_with_metadata()
59 drflac_open_memory()
60 drflac_open_memory_with_metadata()
61 drflac_open_and_read_pcm_frames_s32()
62 drflac_open_and_read_pcm_frames_s16()
63 drflac_open_and_read_pcm_frames_f32()
64 drflac_open_file_and_read_pcm_frames_s32()
65 drflac_open_file_and_read_pcm_frames_s16()
66 drflac_open_file_and_read_pcm_frames_f32()
67 drflac_open_memory_and_read_pcm_frames_s32()
68 drflac_open_memory_and_read_pcm_frames_s16()
69 drflac_open_memory_and_read_pcm_frames_f32()
70
71
72
73Optimizations
74-------------
75Seeking performance has been greatly improved. A new binary search based seeking algorithm has been introduced which significantly
76improves performance over the brute force method which was used when no seek table was present. Seek table based seeking also takes
77advantage of the new binary search seeking system to further improve performance there as well. Note that this depends on CRC which
78means it will be disabled when DR_FLAC_NO_CRC is used.
79
80The SSE4.1 pipeline has been cleaned up and optimized. You should see some improvements with decoding speed of 24-bit files in
81particular. 16-bit streams should also see some improvement.
82
83drflac_read_pcm_frames_s16() has been optimized. Previously this sat on top of drflac_read_pcm_frames_s32() and performed it's s32
84to s16 conversion in a second pass. This is now all done in a single pass. This includes SSE2 and ARM NEON optimized paths.
85
86A minor optimization has been implemented for drflac_read_pcm_frames_s32(). This will now use an SSE2 optimized pipeline for stereo
87channel reconstruction which is the last part of the decoding process.
88
89The ARM build has seen a few improvements. The CLZ (count leading zeroes) and REV (byte swap) instructions are now used when
90compiling with GCC and Clang which is achieved using inline assembly. The CLZ instruction requires ARM architecture version 5 at
91compile time and the REV instruction requires ARM architecture version 6.
92
93An ARM NEON optimized pipeline has been implemented. To enable this you'll need to add -mfpu=neon to the command line when compiling.
94
95
96Removed APIs
97------------
98The following APIs were deprecated in version 0.11.0 and have been completely removed in version 0.12.0:
99
100 drflac_read_s32() -> drflac_read_pcm_frames_s32()
101 drflac_read_s16() -> drflac_read_pcm_frames_s16()
102 drflac_read_f32() -> drflac_read_pcm_frames_f32()
103 drflac_seek_to_sample() -> drflac_seek_to_pcm_frame()
104 drflac_open_and_decode_s32() -> drflac_open_and_read_pcm_frames_s32()
105 drflac_open_and_decode_s16() -> drflac_open_and_read_pcm_frames_s16()
106 drflac_open_and_decode_f32() -> drflac_open_and_read_pcm_frames_f32()
107 drflac_open_and_decode_file_s32() -> drflac_open_file_and_read_pcm_frames_s32()
108 drflac_open_and_decode_file_s16() -> drflac_open_file_and_read_pcm_frames_s16()
109 drflac_open_and_decode_file_f32() -> drflac_open_file_and_read_pcm_frames_f32()
110 drflac_open_and_decode_memory_s32() -> drflac_open_memory_and_read_pcm_frames_s32()
111 drflac_open_and_decode_memory_s16() -> drflac_open_memory_and_read_pcm_frames_s16()
112 drflac_open_and_decode_memory_f32() -> drflac_open_memroy_and_read_pcm_frames_f32()
113
114Prior versions of dr_flac operated on a per-sample basis whereas now it operates on PCM frames. The removed APIs all relate
115to the old per-sample APIs. You now need to use the "pcm_frame" versions.
116*/
117
118
119/*
120Introduction
121============
122dr_flac is a single file library. To use it, do something like the following in one .c file.
123
124 ```c
125 #define DR_FLAC_IMPLEMENTATION
126 #include "dr_flac.h"
127 ```
128
129You 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:
130
131 ```c
132 drflac* pFlac = drflac_open_file("MySong.flac", NULL);
133 if (pFlac == NULL) {
134 // Failed to open FLAC file
135 }
136
137 drflac_int32* pSamples = malloc(pFlac->totalPCMFrameCount * pFlac->channels * sizeof(drflac_int32));
138 drflac_uint64 numberOfInterleavedSamplesActuallyRead = drflac_read_pcm_frames_s32(pFlac, pFlac->totalPCMFrameCount, pSamples);
139 ```
140
141The 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,
142should 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
143a native FLAC stream was opened, however dr_flac has seamless support for Ogg encapsulated FLAC streams as well.
144
145You 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
146samples as it can, up to the amount requested. Later on when you need the next batch of samples, just call it again. Example:
147
148 ```c
149 while (drflac_read_pcm_frames_s32(pFlac, chunkSizeInPCMFrames, pChunkSamples) > 0) {
150 do_something();
151 }
152 ```
153
154You can seek to a specific PCM frame with `drflac_seek_to_pcm_frame()`.
155
156If you just want to quickly decode an entire FLAC file in one go you can do something like this:
157
158 ```c
159 unsigned int channels;
160 unsigned int sampleRate;
161 drflac_uint64 totalPCMFrameCount;
162 drflac_int32* pSampleData = drflac_open_file_and_read_pcm_frames_s32("MySong.flac", &channels, &sampleRate, &totalPCMFrameCount, NULL);
163 if (pSampleData == NULL) {
164 // Failed to open and decode FLAC file.
165 }
166
167 ...
168
169 drflac_free(pSampleData, NULL);
170 ```
171
172You can read samples as signed 16-bit integer and 32-bit floating-point PCM with the *_s16() and *_f32() family of APIs respectively, but note that these
173should be considered lossy.
174
175
176If you need access to metadata (album art, etc.), use `drflac_open_with_metadata()`, `drflac_open_file_with_metdata()` or `drflac_open_memory_with_metadata()`.
177The 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
178reports metadata to the application through the use of a callback, and every metadata block is reported before `drflac_open_with_metdata()` returns.
179
180The main opening APIs (`drflac_open()`, etc.) will fail if the header is not present. The presents a problem in certain scenarios such as broadcast style
181streams or internet radio where the header may not be present because the user has started playback mid-stream. To handle this, use the relaxed APIs:
182
183 `drflac_open_relaxed()`
184 `drflac_open_with_metadata_relaxed()`
185
186It is not recommended to use these APIs for file based streams because a missing header would usually indicate a corrupt or perverse file. In addition, these
187APIs can take a long time to initialize because they may need to spend a lot of time finding the first frame.
188
189
190
191Build Options
192=============
193#define these options before including this file.
194
195#define DR_FLAC_NO_STDIO
196 Disable `drflac_open_file()` and family.
197
198#define DR_FLAC_NO_OGG
199 Disables support for Ogg/FLAC streams.
200
201#define DR_FLAC_BUFFER_SIZE <number>
202 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.
203 Larger values means more memory, but better performance. My tests show diminishing returns after about 4KB (which is the default). Consider reducing this if
204 you have a very efficient implementation of onRead(), or increase it if it's very inefficient. Must be a multiple of 8.
205
206#define DR_FLAC_NO_CRC
207 Disables CRC checks. This will offer a performance boost when CRC is unnecessary. This will disable binary search seeking. When seeking, the seek table will
208 be used if available. Otherwise the seek will be performed using brute force.
209
210#define DR_FLAC_NO_SIMD
211 Disables SIMD optimizations (SSE on x86/x64 architectures, NEON on ARM architectures). Use this if you are having compatibility issues with your compiler.
212
213#define DR_FLAC_NO_WCHAR
214 Disables all functions ending with `_w`. Use this if your compiler does not provide wchar.h. Not required if DR_FLAC_NO_STDIO is also defined.
215
216
217
218Notes
219=====
220- dr_flac does not support changing the sample rate nor channel count mid stream.
221- dr_flac is not thread-safe, but its APIs can be called from any thread so long as you do your own synchronization.
222- When using Ogg encapsulation, a corrupted metadata block will result in `drflac_open_with_metadata()` and `drflac_open()` returning inconsistent samples due
223 to differences in corrupted stream recorvery logic between the two APIs.
224*/
225
226#ifndef dr_flac_h
227#define dr_flac_h
228
229#ifdef __cplusplus
230extern "C" {
231#endif
232
233#define DRFLAC_STRINGIFY(x) #x
234#define DRFLAC_XSTRINGIFY(x) DRFLAC_STRINGIFY(x)
235
236#define DRFLAC_VERSION_MAJOR 0
237#define DRFLAC_VERSION_MINOR 12
238#define DRFLAC_VERSION_REVISION 42
239#define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION)
240
241#include <stddef.h> /* For size_t. */
242
243/* Sized Types */
244typedef signed char drflac_int8;
245typedef unsigned char drflac_uint8;
246typedef signed short drflac_int16;
247typedef unsigned short drflac_uint16;
248typedef signed int drflac_int32;
249typedef unsigned int drflac_uint32;
250#if defined(_MSC_VER) && !defined(__clang__)
251 typedef signed __int64 drflac_int64;
252 typedef unsigned __int64 drflac_uint64;
253#else
254 #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
255 #pragma GCC diagnostic push
256 #pragma GCC diagnostic ignored "-Wlong-long"
257 #if defined(__clang__)
258 #pragma GCC diagnostic ignored "-Wc++11-long-long"
259 #endif
260 #endif
261 typedef signed long long drflac_int64;
262 typedef unsigned long long drflac_uint64;
263 #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
264 #pragma GCC diagnostic pop
265 #endif
266#endif
267#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__)
268 typedef drflac_uint64 drflac_uintptr;
269#else
270 typedef drflac_uint32 drflac_uintptr;
271#endif
272typedef drflac_uint8 drflac_bool8;
273typedef drflac_uint32 drflac_bool32;
274#define DRFLAC_TRUE 1
275#define DRFLAC_FALSE 0
276/* End Sized Types */
277
278/* Decorations */
279#if !defined(DRFLAC_API)
280 #if defined(DRFLAC_DLL)
281 #if defined(_WIN32)
282 #define DRFLAC_DLL_IMPORT __declspec(dllimport)
283 #define DRFLAC_DLL_EXPORT __declspec(dllexport)
284 #define DRFLAC_DLL_PRIVATE static
285 #else
286 #if defined(__GNUC__) && __GNUC__ >= 4
287 #define DRFLAC_DLL_IMPORT __attribute__((visibility("default")))
288 #define DRFLAC_DLL_EXPORT __attribute__((visibility("default")))
289 #define DRFLAC_DLL_PRIVATE __attribute__((visibility("hidden")))
290 #else
291 #define DRFLAC_DLL_IMPORT
292 #define DRFLAC_DLL_EXPORT
293 #define DRFLAC_DLL_PRIVATE static
294 #endif
295 #endif
296
297 #if defined(DR_FLAC_IMPLEMENTATION) || defined(DRFLAC_IMPLEMENTATION)
298 #define DRFLAC_API DRFLAC_DLL_EXPORT
299 #else
300 #define DRFLAC_API DRFLAC_DLL_IMPORT
301 #endif
302 #define DRFLAC_PRIVATE DRFLAC_DLL_PRIVATE
303 #else
304 #define DRFLAC_API extern
305 #define DRFLAC_PRIVATE static
306 #endif
307#endif
308/* End Decorations */
309
310#if defined(_MSC_VER) && _MSC_VER >= 1700 /* Visual Studio 2012 */
311 #define DRFLAC_DEPRECATED __declspec(deprecated)
312#elif (defined(__GNUC__) && __GNUC__ >= 4) /* GCC 4 */
313 #define DRFLAC_DEPRECATED __attribute__((deprecated))
314#elif defined(__has_feature) /* Clang */
315 #if __has_feature(attribute_deprecated)
316 #define DRFLAC_DEPRECATED __attribute__((deprecated))
317 #else
318 #define DRFLAC_DEPRECATED
319 #endif
320#else
321 #define DRFLAC_DEPRECATED
322#endif
323
324DRFLAC_API void drflac_version(drflac_uint32* pMajor, drflac_uint32* pMinor, drflac_uint32* pRevision);
325DRFLAC_API const char* drflac_version_string(void);
326
327/* Allocation Callbacks */
328typedef struct
329{
330 void* pUserData;
331 void* (* onMalloc)(size_t sz, void* pUserData);
332 void* (* onRealloc)(void* p, size_t sz, void* pUserData);
333 void (* onFree)(void* p, void* pUserData);
334} drflac_allocation_callbacks;
335/* End Allocation Callbacks */
336
337/*
338As 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,
339but 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.
340*/
341#ifndef DR_FLAC_BUFFER_SIZE
342#define DR_FLAC_BUFFER_SIZE 4096
343#endif
344
345
346/* Architecture Detection */
347#if defined(_WIN64) || defined(_LP64) || defined(__LP64__)
348#define DRFLAC_64BIT
349#endif
350
351#if defined(__x86_64__) || defined(_M_X64)
352 #define DRFLAC_X64
353#elif defined(__i386) || defined(_M_IX86)
354 #define DRFLAC_X86
355#elif defined(__arm__) || defined(_M_ARM) || defined(__arm64) || defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64)
356 #define DRFLAC_ARM
357#endif
358/* End Architecture Detection */
359
360
361#ifdef DRFLAC_64BIT
362typedef drflac_uint64 drflac_cache_t;
363#else
364typedef drflac_uint32 drflac_cache_t;
365#endif
366
367/* The various metadata block types. */
368#define DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO 0
369#define DRFLAC_METADATA_BLOCK_TYPE_PADDING 1
370#define DRFLAC_METADATA_BLOCK_TYPE_APPLICATION 2
371#define DRFLAC_METADATA_BLOCK_TYPE_SEEKTABLE 3
372#define DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT 4
373#define DRFLAC_METADATA_BLOCK_TYPE_CUESHEET 5
374#define DRFLAC_METADATA_BLOCK_TYPE_PICTURE 6
375#define DRFLAC_METADATA_BLOCK_TYPE_INVALID 127
376
377/* The various picture types specified in the PICTURE block. */
378#define DRFLAC_PICTURE_TYPE_OTHER 0
379#define DRFLAC_PICTURE_TYPE_FILE_ICON 1
380#define DRFLAC_PICTURE_TYPE_OTHER_FILE_ICON 2
381#define DRFLAC_PICTURE_TYPE_COVER_FRONT 3
382#define DRFLAC_PICTURE_TYPE_COVER_BACK 4
383#define DRFLAC_PICTURE_TYPE_LEAFLET_PAGE 5
384#define DRFLAC_PICTURE_TYPE_MEDIA 6
385#define DRFLAC_PICTURE_TYPE_LEAD_ARTIST 7
386#define DRFLAC_PICTURE_TYPE_ARTIST 8
387#define DRFLAC_PICTURE_TYPE_CONDUCTOR 9
388#define DRFLAC_PICTURE_TYPE_BAND 10
389#define DRFLAC_PICTURE_TYPE_COMPOSER 11
390#define DRFLAC_PICTURE_TYPE_LYRICIST 12
391#define DRFLAC_PICTURE_TYPE_RECORDING_LOCATION 13
392#define DRFLAC_PICTURE_TYPE_DURING_RECORDING 14
393#define DRFLAC_PICTURE_TYPE_DURING_PERFORMANCE 15
394#define DRFLAC_PICTURE_TYPE_SCREEN_CAPTURE 16
395#define DRFLAC_PICTURE_TYPE_BRIGHT_COLORED_FISH 17
396#define DRFLAC_PICTURE_TYPE_ILLUSTRATION 18
397#define DRFLAC_PICTURE_TYPE_BAND_LOGOTYPE 19
398#define DRFLAC_PICTURE_TYPE_PUBLISHER_LOGOTYPE 20
399
400typedef enum
401{
402 drflac_container_native,
403 drflac_container_ogg,
404 drflac_container_unknown
405} drflac_container;
406
407typedef enum
408{
409 drflac_seek_origin_start,
410 drflac_seek_origin_current
411} drflac_seek_origin;
412
413/* The order of members in this structure is important because we map this directly to the raw data within the SEEKTABLE metadata block. */
414typedef struct
415{
416 drflac_uint64 firstPCMFrame;
417 drflac_uint64 flacFrameOffset; /* The offset from the first byte of the header of the first frame. */
418 drflac_uint16 pcmFrameCount;
419} drflac_seekpoint;
420
421typedef struct
422{
423 drflac_uint16 minBlockSizeInPCMFrames;
424 drflac_uint16 maxBlockSizeInPCMFrames;
425 drflac_uint32 minFrameSizeInPCMFrames;
426 drflac_uint32 maxFrameSizeInPCMFrames;
427 drflac_uint32 sampleRate;
428 drflac_uint8 channels;
429 drflac_uint8 bitsPerSample;
430 drflac_uint64 totalPCMFrameCount;
431 drflac_uint8 md5[16];
432} drflac_streaminfo;
433
434typedef struct
435{
436 /*
437 The metadata type. Use this to know how to interpret the data below. Will be set to one of the
438 DRFLAC_METADATA_BLOCK_TYPE_* tokens.
439 */
440 drflac_uint32 type;
441
442 /*
443 A pointer to the raw data. This points to a temporary buffer so don't hold on to it. It's best to
444 not modify the contents of this buffer. Use the structures below for more meaningful and structured
445 information about the metadata. It's possible for this to be null.
446 */
447 const void* pRawData;
448
449 /* The size in bytes of the block and the buffer pointed to by pRawData if it's non-NULL. */
450 drflac_uint32 rawDataSize;
451
452 union
453 {
454 drflac_streaminfo streaminfo;
455
456 struct
457 {
458 int unused;
459 } padding;
460
461 struct
462 {
463 drflac_uint32 id;
464 const void* pData;
465 drflac_uint32 dataSize;
466 } application;
467
468 struct
469 {
470 drflac_uint32 seekpointCount;
471 const drflac_seekpoint* pSeekpoints;
472 } seektable;
473
474 struct
475 {
476 drflac_uint32 vendorLength;
477 const char* vendor;
478 drflac_uint32 commentCount;
479 const void* pComments;
480 } vorbis_comment;
481
482 struct
483 {
484 char catalog[128];
485 drflac_uint64 leadInSampleCount;
486 drflac_bool32 isCD;
487 drflac_uint8 trackCount;
488 const void* pTrackData;
489 } cuesheet;
490
491 struct
492 {
493 drflac_uint32 type;
494 drflac_uint32 mimeLength;
495 const char* mime;
496 drflac_uint32 descriptionLength;
497 const char* description;
498 drflac_uint32 width;
499 drflac_uint32 height;
500 drflac_uint32 colorDepth;
501 drflac_uint32 indexColorCount;
502 drflac_uint32 pictureDataSize;
503 const drflac_uint8* pPictureData;
504 } picture;
505 } data;
506} drflac_metadata;
507
508
509/*
510Callback for when data needs to be read from the client.
511
512
513Parameters
514----------
515pUserData (in)
516 The user data that was passed to drflac_open() and family.
517
518pBufferOut (out)
519 The output buffer.
520
521bytesToRead (in)
522 The number of bytes to read.
523
524
525Return Value
526------------
527The number of bytes actually read.
528
529
530Remarks
531-------
532A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback until either the entire bytesToRead is filled or
533you have reached the end of the stream.
534*/
535typedef size_t (* drflac_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead);
536
537/*
538Callback for when data needs to be seeked.
539
540
541Parameters
542----------
543pUserData (in)
544 The user data that was passed to drflac_open() and family.
545
546offset (in)
547 The number of bytes to move, relative to the origin. Will never be negative.
548
549origin (in)
550 The origin of the seek - the current position or the start of the stream.
551
552
553Return Value
554------------
555Whether or not the seek was successful.
556
557
558Remarks
559-------
560The 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
561either drflac_seek_origin_start or drflac_seek_origin_current.
562
563When seeking to a PCM frame using drflac_seek_to_pcm_frame(), dr_flac may call this with an offset beyond the end of the FLAC stream. This needs to be detected
564and handled by returning DRFLAC_FALSE.
565*/
566typedef drflac_bool32 (* drflac_seek_proc)(void* pUserData, int offset, drflac_seek_origin origin);
567
568/*
569Callback for when a metadata block is read.
570
571
572Parameters
573----------
574pUserData (in)
575 The user data that was passed to drflac_open() and family.
576
577pMetadata (in)
578 A pointer to a structure containing the data of the metadata block.
579
580
581Remarks
582-------
583Use pMetadata->type to determine which metadata block is being handled and how to read the data. This
584will be set to one of the DRFLAC_METADATA_BLOCK_TYPE_* tokens.
585*/
586typedef void (* drflac_meta_proc)(void* pUserData, drflac_metadata* pMetadata);
587
588
589/* Structure for internal use. Only used for decoders opened with drflac_open_memory. */
590typedef struct
591{
592 const drflac_uint8* data;
593 size_t dataSize;
594 size_t currentReadPos;
595} drflac__memory_stream;
596
597/* Structure for internal use. Used for bit streaming. */
598typedef struct
599{
600 /* The function to call when more data needs to be read. */
601 drflac_read_proc onRead;
602
603 /* The function to call when the current read position needs to be moved. */
604 drflac_seek_proc onSeek;
605
606 /* The user data to pass around to onRead and onSeek. */
607 void* pUserData;
608
609
610 /*
611 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
612 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
613 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).
614 */
615 size_t unalignedByteCount;
616
617 /* The content of the unaligned bytes. */
618 drflac_cache_t unalignedCache;
619
620 /* The index of the next valid cache line in the "L2" cache. */
621 drflac_uint32 nextL2Line;
622
623 /* The number of bits that have been consumed by the cache. This is used to determine how many valid bits are remaining. */
624 drflac_uint32 consumedBits;
625
626 /*
627 The cached data which was most recently read from the client. There are two levels of cache. Data flows as such:
628 Client -> L2 -> L1. The L2 -> L1 movement is aligned and runs on a fast path in just a few instructions.
629 */
630 drflac_cache_t cacheL2[DR_FLAC_BUFFER_SIZE/sizeof(drflac_cache_t)];
631 drflac_cache_t cache;
632
633 /*
634 CRC-16. This is updated whenever bits are read from the bit stream. Manually set this to 0 to reset the CRC. For FLAC, this
635 is reset to 0 at the beginning of each frame.
636 */
637 drflac_uint16 crc16;
638 drflac_cache_t crc16Cache; /* A cache for optimizing CRC calculations. This is filled when when the L1 cache is reloaded. */
639 drflac_uint32 crc16CacheIgnoredBytes; /* The number of bytes to ignore when updating the CRC-16 from the CRC-16 cache. */
640} drflac_bs;
641
642typedef struct
643{
644 /* The type of the subframe: SUBFRAME_CONSTANT, SUBFRAME_VERBATIM, SUBFRAME_FIXED or SUBFRAME_LPC. */
645 drflac_uint8 subframeType;
646
647 /* The number of wasted bits per sample as specified by the sub-frame header. */
648 drflac_uint8 wastedBitsPerSample;
649
650 /* The order to use for the prediction stage for SUBFRAME_FIXED and SUBFRAME_LPC. */
651 drflac_uint8 lpcOrder;
652
653 /* A pointer to the buffer containing the decoded samples in the subframe. This pointer is an offset from drflac::pExtraData. */
654 drflac_int32* pSamplesS32;
655} drflac_subframe;
656
657typedef struct
658{
659 /*
660 If the stream uses variable block sizes, this will be set to the index of the first PCM frame. If fixed block sizes are used, this will
661 always be set to 0. This is 64-bit because the decoded PCM frame number will be 36 bits.
662 */
663 drflac_uint64 pcmFrameNumber;
664
665 /*
666 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. This
667 is 32-bit because in fixed block sizes, the maximum frame number will be 31 bits.
668 */
669 drflac_uint32 flacFrameNumber;
670
671 /* The sample rate of this frame. */
672 drflac_uint32 sampleRate;
673
674 /* The number of PCM frames in each sub-frame within this frame. */
675 drflac_uint16 blockSizeInPCMFrames;
676
677 /*
678 The channel assignment of this frame. This is not always set to the channel count. If interchannel decorrelation is being used this
679 will be set to DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE, DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE or DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE.
680 */
681 drflac_uint8 channelAssignment;
682
683 /* The number of bits per sample within this frame. */
684 drflac_uint8 bitsPerSample;
685
686 /* The frame's CRC. */
687 drflac_uint8 crc8;
688} drflac_frame_header;
689
690typedef struct
691{
692 /* The header. */
693 drflac_frame_header header;
694
695 /*
696 The number of PCM frames left to be read in this FLAC frame. This is initially set to the block size. As PCM frames are read,
697 this will be decremented. When it reaches 0, the decoder will see this frame as fully consumed and load the next frame.
698 */
699 drflac_uint32 pcmFramesRemaining;
700
701 /* The list of sub-frames within the frame. There is one sub-frame for each channel, and there's a maximum of 8 channels. */
702 drflac_subframe subframes[8];
703} drflac_frame;
704
705typedef struct
706{
707 /* The function to call when a metadata block is read. */
708 drflac_meta_proc onMeta;
709
710 /* The user data posted to the metadata callback function. */
711 void* pUserDataMD;
712
713 /* Memory allocation callbacks. */
714 drflac_allocation_callbacks allocationCallbacks;
715
716
717 /* The sample rate. Will be set to something like 44100. */
718 drflac_uint32 sampleRate;
719
720 /*
721 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
722 value specified in the STREAMINFO block.
723 */
724 drflac_uint8 channels;
725
726 /* The bits per sample. Will be set to something like 16, 24, etc. */
727 drflac_uint8 bitsPerSample;
728
729 /* The maximum block size, in samples. This number represents the number of samples in each channel (not combined). */
730 drflac_uint16 maxBlockSizeInPCMFrames;
731
732 /*
733 The total number of PCM Frames making up the stream. Can be 0 in which case it's still a valid stream, but just means
734 the total PCM frame count is unknown. Likely the case with streams like internet radio.
735 */
736 drflac_uint64 totalPCMFrameCount;
737
738
739 /* The container type. This is set based on whether or not the decoder was opened from a native or Ogg stream. */
740 drflac_container container;
741
742 /* The number of seekpoints in the seektable. */
743 drflac_uint32 seekpointCount;
744
745
746 /* Information about the frame the decoder is currently sitting on. */
747 drflac_frame currentFLACFrame;
748
749
750 /* The index of the PCM frame the decoder is currently sitting on. This is only used for seeking. */
751 drflac_uint64 currentPCMFrame;
752
753 /* The position of the first FLAC frame in the stream. This is only ever used for seeking. */
754 drflac_uint64 firstFLACFramePosInBytes;
755
756
757 /* A hack to avoid a malloc() when opening a decoder with drflac_open_memory(). */
758 drflac__memory_stream memoryStream;
759
760
761 /* A pointer to the decoded sample data. This is an offset of pExtraData. */
762 drflac_int32* pDecodedSamples;
763
764 /* A pointer to the seek table. This is an offset of pExtraData, or NULL if there is no seek table. */
765 drflac_seekpoint* pSeekpoints;
766
767 /* Internal use only. Only used with Ogg containers. Points to a drflac_oggbs object. This is an offset of pExtraData. */
768 void* _oggbs;
769
770 /* Internal use only. Used for profiling and testing different seeking modes. */
771 drflac_bool32 _noSeekTableSeek : 1;
772 drflac_bool32 _noBinarySearchSeek : 1;
773 drflac_bool32 _noBruteForceSeek : 1;
774
775 /* The bit streamer. The raw FLAC data is fed through this object. */
776 drflac_bs bs;
777
778 /* Variable length extra data. We attach this to the end of the object so we can avoid unnecessary mallocs. */
779 drflac_uint8 pExtraData[1];
780} drflac;
781
782
783/*
784Opens a FLAC decoder.
785
786
787Parameters
788----------
789onRead (in)
790 The function to call when data needs to be read from the client.
791
792onSeek (in)
793 The function to call when the read position of the client data needs to move.
794
795pUserData (in, optional)
796 A pointer to application defined data that will be passed to onRead and onSeek.
797
798pAllocationCallbacks (in, optional)
799 A pointer to application defined callbacks for managing memory allocations.
800
801
802Return Value
803------------
804Returns a pointer to an object representing the decoder.
805
806
807Remarks
808-------
809Close the decoder with `drflac_close()`.
810
811`pAllocationCallbacks` can be NULL in which case it will use `DRFLAC_MALLOC`, `DRFLAC_REALLOC` and `DRFLAC_FREE`.
812
813This function will automatically detect whether or not you are attempting to open a native or Ogg encapsulated FLAC, both of which should work seamlessly
814without any manual intervention. Ogg encapsulation also works with multiplexed streams which basically means it can play FLAC encoded audio tracks in videos.
815
816This 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
817from a block of memory respectively.
818
819The STREAMINFO block must be present for this to succeed. Use `drflac_open_relaxed()` to open a FLAC stream where the header may not be present.
820
821Use `drflac_open_with_metadata()` if you need access to metadata.
822
823
824Seek Also
825---------
826drflac_open_file()
827drflac_open_memory()
828drflac_open_with_metadata()
829drflac_close()
830*/
831DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
832
833/*
834Opens a FLAC stream with relaxed validation of the header block.
835
836
837Parameters
838----------
839onRead (in)
840 The function to call when data needs to be read from the client.
841
842onSeek (in)
843 The function to call when the read position of the client data needs to move.
844
845container (in)
846 Whether or not the FLAC stream is encapsulated using standard FLAC encapsulation or Ogg encapsulation.
847
848pUserData (in, optional)
849 A pointer to application defined data that will be passed to onRead and onSeek.
850
851pAllocationCallbacks (in, optional)
852 A pointer to application defined callbacks for managing memory allocations.
853
854
855Return Value
856------------
857A pointer to an object representing the decoder.
858
859
860Remarks
861-------
862The same as drflac_open(), except attempts to open the stream even when a header block is not present.
863
864Because the header is not necessarily available, the caller must explicitly define the container (Native or Ogg). Do not set this to `drflac_container_unknown`
865as that is for internal use only.
866
867Opening in relaxed mode will continue reading data from onRead until it finds a valid frame. If a frame is never found it will continue forever. To abort,
868force your `onRead` callback to return 0, which dr_flac will use as an indicator that the end of the stream was found.
869
870Use `drflac_open_with_metadata_relaxed()` if you need access to metadata.
871*/
872DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
873
874/*
875Opens a FLAC decoder and notifies the caller of the metadata chunks (album art, etc.).
876
877
878Parameters
879----------
880onRead (in)
881 The function to call when data needs to be read from the client.
882
883onSeek (in)
884 The function to call when the read position of the client data needs to move.
885
886onMeta (in)
887 The function to call for every metadata block.
888
889pUserData (in, optional)
890 A pointer to application defined data that will be passed to onRead, onSeek and onMeta.
891
892pAllocationCallbacks (in, optional)
893 A pointer to application defined callbacks for managing memory allocations.
894
895
896Return Value
897------------
898A pointer to an object representing the decoder.
899
900
901Remarks
902-------
903Close the decoder with `drflac_close()`.
904
905`pAllocationCallbacks` can be NULL in which case it will use `DRFLAC_MALLOC`, `DRFLAC_REALLOC` and `DRFLAC_FREE`.
906
907This is slower than `drflac_open()`, so avoid this one if you don't need metadata. Internally, this will allocate and free memory on the heap for every
908metadata block except for STREAMINFO and PADDING blocks.
909
910The caller is notified of the metadata via the `onMeta` callback. All metadata blocks will be handled before the function returns. This callback takes a
911pointer to a `drflac_metadata` object which is a union containing the data of all relevant metadata blocks. Use the `type` member to discriminate against
912the different metadata types.
913
914The STREAMINFO block must be present for this to succeed. Use `drflac_open_with_metadata_relaxed()` to open a FLAC stream where the header may not be present.
915
916Note that this will behave inconsistently with `drflac_open()` if the stream is an Ogg encapsulated stream and a metadata block is corrupted. This is due to
917the way the Ogg stream recovers from corrupted pages. When `drflac_open_with_metadata()` is being used, the open routine will try to read the contents of the
918metadata block, whereas `drflac_open()` will simply seek past it (for the sake of efficiency). This inconsistency can result in different samples being
919returned depending on whether or not the stream is being opened with metadata.
920
921
922Seek Also
923---------
924drflac_open_file_with_metadata()
925drflac_open_memory_with_metadata()
926drflac_open()
927drflac_close()
928*/
929DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
930
931/*
932The same as drflac_open_with_metadata(), except attempts to open the stream even when a header block is not present.
933
934See Also
935--------
936drflac_open_with_metadata()
937drflac_open_relaxed()
938*/
939DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
940
941/*
942Closes the given FLAC decoder.
943
944
945Parameters
946----------
947pFlac (in)
948 The decoder to close.
949
950
951Remarks
952-------
953This will destroy the decoder object.
954
955
956See Also
957--------
958drflac_open()
959drflac_open_with_metadata()
960drflac_open_file()
961drflac_open_file_w()
962drflac_open_file_with_metadata()
963drflac_open_file_with_metadata_w()
964drflac_open_memory()
965drflac_open_memory_with_metadata()
966*/
967DRFLAC_API void drflac_close(drflac* pFlac);
968
969
970/*
971Reads sample data from the given FLAC decoder, output as interleaved signed 32-bit PCM.
972
973
974Parameters
975----------
976pFlac (in)
977 The decoder.
978
979framesToRead (in)
980 The number of PCM frames to read.
981
982pBufferOut (out, optional)
983 A pointer to the buffer that will receive the decoded samples.
984
985
986Return Value
987------------
988Returns the number of PCM frames actually read. If the return value is less than `framesToRead` it has reached the end.
989
990
991Remarks
992-------
993pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of frames seeked.
994*/
995DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s32(drflac* pFlac, drflac_uint64 framesToRead, drflac_int32* pBufferOut);
996
997
998/*
999Reads sample data from the given FLAC decoder, output as interleaved signed 16-bit PCM.
1000
1001
1002Parameters
1003----------
1004pFlac (in)
1005 The decoder.
1006
1007framesToRead (in)
1008 The number of PCM frames to read.
1009
1010pBufferOut (out, optional)
1011 A pointer to the buffer that will receive the decoded samples.
1012
1013
1014Return Value
1015------------
1016Returns the number of PCM frames actually read. If the return value is less than `framesToRead` it has reached the end.
1017
1018
1019Remarks
1020-------
1021pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of frames seeked.
1022
1023Note that this is lossy for streams where the bits per sample is larger than 16.
1024*/
1025DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s16(drflac* pFlac, drflac_uint64 framesToRead, drflac_int16* pBufferOut);
1026
1027/*
1028Reads sample data from the given FLAC decoder, output as interleaved 32-bit floating point PCM.
1029
1030
1031Parameters
1032----------
1033pFlac (in)
1034 The decoder.
1035
1036framesToRead (in)
1037 The number of PCM frames to read.
1038
1039pBufferOut (out, optional)
1040 A pointer to the buffer that will receive the decoded samples.
1041
1042
1043Return Value
1044------------
1045Returns the number of PCM frames actually read. If the return value is less than `framesToRead` it has reached the end.
1046
1047
1048Remarks
1049-------
1050pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of frames seeked.
1051
1052Note that this should be considered lossy due to the nature of floating point numbers not being able to exactly represent every possible number.
1053*/
1054DRFLAC_API drflac_uint64 drflac_read_pcm_frames_f32(drflac* pFlac, drflac_uint64 framesToRead, float* pBufferOut);
1055
1056/*
1057Seeks to the PCM frame at the given index.
1058
1059
1060Parameters
1061----------
1062pFlac (in)
1063 The decoder.
1064
1065pcmFrameIndex (in)
1066 The index of the PCM frame to seek to. See notes below.
1067
1068
1069Return Value
1070-------------
1071`DRFLAC_TRUE` if successful; `DRFLAC_FALSE` otherwise.
1072*/
1073DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex);
1074
1075
1076
1077#ifndef DR_FLAC_NO_STDIO
1078/*
1079Opens a FLAC decoder from the file at the given path.
1080
1081
1082Parameters
1083----------
1084pFileName (in)
1085 The path of the file to open, either absolute or relative to the current directory.
1086
1087pAllocationCallbacks (in, optional)
1088 A pointer to application defined callbacks for managing memory allocations.
1089
1090
1091Return Value
1092------------
1093A pointer to an object representing the decoder.
1094
1095
1096Remarks
1097-------
1098Close the decoder with drflac_close().
1099
1100
1101Remarks
1102-------
1103This 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
1104at any given time, so keep this mind if you have many decoders open at the same time.
1105
1106
1107See Also
1108--------
1109drflac_open_file_with_metadata()
1110drflac_open()
1111drflac_close()
1112*/
1113DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks);
1114DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks);
1115
1116/*
1117Opens a FLAC decoder from the file at the given path and notifies the caller of the metadata chunks (album art, etc.)
1118
1119
1120Parameters
1121----------
1122pFileName (in)
1123 The path of the file to open, either absolute or relative to the current directory.
1124
1125pAllocationCallbacks (in, optional)
1126 A pointer to application defined callbacks for managing memory allocations.
1127
1128onMeta (in)
1129 The callback to fire for each metadata block.
1130
1131pUserData (in)
1132 A pointer to the user data to pass to the metadata callback.
1133
1134pAllocationCallbacks (in)
1135 A pointer to application defined callbacks for managing memory allocations.
1136
1137
1138Remarks
1139-------
1140Look at the documentation for drflac_open_with_metadata() for more information on how metadata is handled.
1141
1142
1143See Also
1144--------
1145drflac_open_with_metadata()
1146drflac_open()
1147drflac_close()
1148*/
1149DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
1150DRFLAC_API drflac* drflac_open_file_with_metadata_w(const wchar_t* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
1151#endif
1152
1153/*
1154Opens a FLAC decoder from a pre-allocated block of memory
1155
1156
1157Parameters
1158----------
1159pData (in)
1160 A pointer to the raw encoded FLAC data.
1161
1162dataSize (in)
1163 The size in bytes of `data`.
1164
1165pAllocationCallbacks (in)
1166 A pointer to application defined callbacks for managing memory allocations.
1167
1168
1169Return Value
1170------------
1171A pointer to an object representing the decoder.
1172
1173
1174Remarks
1175-------
1176This 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.
1177
1178
1179See Also
1180--------
1181drflac_open()
1182drflac_close()
1183*/
1184DRFLAC_API drflac* drflac_open_memory(const void* pData, size_t dataSize, const drflac_allocation_callbacks* pAllocationCallbacks);
1185
1186/*
1187Opens a FLAC decoder from a pre-allocated block of memory and notifies the caller of the metadata chunks (album art, etc.)
1188
1189
1190Parameters
1191----------
1192pData (in)
1193 A pointer to the raw encoded FLAC data.
1194
1195dataSize (in)
1196 The size in bytes of `data`.
1197
1198onMeta (in)
1199 The callback to fire for each metadata block.
1200
1201pUserData (in)
1202 A pointer to the user data to pass to the metadata callback.
1203
1204pAllocationCallbacks (in)
1205 A pointer to application defined callbacks for managing memory allocations.
1206
1207
1208Remarks
1209-------
1210Look at the documentation for drflac_open_with_metadata() for more information on how metadata is handled.
1211
1212
1213See Also
1214-------
1215drflac_open_with_metadata()
1216drflac_open()
1217drflac_close()
1218*/
1219DRFLAC_API drflac* drflac_open_memory_with_metadata(const void* pData, size_t dataSize, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
1220
1221
1222
1223/* High Level APIs */
1224
1225/*
1226Opens a FLAC stream from the given callbacks and fully decodes it in a single operation. The return value is a
1227pointer to the sample data as interleaved signed 32-bit PCM. The returned data must be freed with drflac_free().
1228
1229You can pass in custom memory allocation callbacks via the pAllocationCallbacks parameter. This can be NULL in which
1230case it will use DRFLAC_MALLOC, DRFLAC_REALLOC and DRFLAC_FREE.
1231
1232Sometimes a FLAC file won't keep track of the total sample count. In this situation the function will continuously
1233read samples into a dynamically sized buffer on the heap until no samples are left.
1234
1235Do not call this function on a broadcast type of stream (like internet radio streams and whatnot).
1236*/
1237DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
1238
1239/* Same as drflac_open_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. */
1240DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
1241
1242/* Same as drflac_open_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. */
1243DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
1244
1245#ifndef DR_FLAC_NO_STDIO
1246/* Same as drflac_open_and_read_pcm_frames_s32() except opens the decoder from a file. */
1247DRFLAC_API drflac_int32* drflac_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
1248
1249/* Same as drflac_open_file_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. */
1250DRFLAC_API drflac_int16* drflac_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
1251
1252/* Same as drflac_open_file_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. */
1253DRFLAC_API float* drflac_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
1254#endif
1255
1256/* Same as drflac_open_and_read_pcm_frames_s32() except opens the decoder from a block of memory. */
1257DRFLAC_API drflac_int32* drflac_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
1258
1259/* Same as drflac_open_memory_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. */
1260DRFLAC_API drflac_int16* drflac_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
1261
1262/* Same as drflac_open_memory_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. */
1263DRFLAC_API float* drflac_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
1264
1265/*
1266Frees memory that was allocated internally by dr_flac.
1267
1268Set pAllocationCallbacks to the same object that was passed to drflac_open_*_and_read_pcm_frames_*(). If you originally passed in NULL, pass in NULL for this.
1269*/
1270DRFLAC_API void drflac_free(void* p, const drflac_allocation_callbacks* pAllocationCallbacks);
1271
1272
1273/* Structure representing an iterator for vorbis comments in a VORBIS_COMMENT metadata block. */
1274typedef struct
1275{
1276 drflac_uint32 countRemaining;
1277 const char* pRunningData;
1278} drflac_vorbis_comment_iterator;
1279
1280/*
1281Initializes a vorbis comment iterator. This can be used for iterating over the vorbis comments in a VORBIS_COMMENT
1282metadata block.
1283*/
1284DRFLAC_API void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const void* pComments);
1285
1286/*
1287Goes to the next vorbis comment in the given iterator. If null is returned it means there are no more comments. The
1288returned string is NOT null terminated.
1289*/
1290DRFLAC_API const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut);
1291
1292
1293/* Structure representing an iterator for cuesheet tracks in a CUESHEET metadata block. */
1294typedef struct
1295{
1296 drflac_uint32 countRemaining;
1297 const char* pRunningData;
1298} drflac_cuesheet_track_iterator;
1299
1300/* The order of members here is important because we map this directly to the raw data within the CUESHEET metadata block. */
1301typedef struct
1302{
1303 drflac_uint64 offset;
1304 drflac_uint8 index;
1305 drflac_uint8 reserved[3];
1306} drflac_cuesheet_track_index;
1307
1308typedef struct
1309{
1310 drflac_uint64 offset;
1311 drflac_uint8 trackNumber;
1312 char ISRC[12];
1313 drflac_bool8 isAudio;
1314 drflac_bool8 preEmphasis;
1315 drflac_uint8 indexCount;
1316 const drflac_cuesheet_track_index* pIndexPoints;
1317} drflac_cuesheet_track;
1318
1319/*
1320Initializes a cuesheet track iterator. This can be used for iterating over the cuesheet tracks in a CUESHEET metadata
1321block.
1322*/
1323DRFLAC_API void drflac_init_cuesheet_track_iterator(drflac_cuesheet_track_iterator* pIter, drflac_uint32 trackCount, const void* pTrackData);
1324
1325/* Goes to the next cuesheet track in the given iterator. If DRFLAC_FALSE is returned it means there are no more comments. */
1326DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter, drflac_cuesheet_track* pCuesheetTrack);
1327
1328
1329#ifdef __cplusplus
1330}
1331#endif
1332#endif /* dr_flac_h */
1333
1334
1335/************************************************************************************************************************************************************
1336 ************************************************************************************************************************************************************
1337
1338 IMPLEMENTATION
1339
1340 ************************************************************************************************************************************************************
1341 ************************************************************************************************************************************************************/
1342#if defined(DR_FLAC_IMPLEMENTATION) || defined(DRFLAC_IMPLEMENTATION)
1343#ifndef dr_flac_c
1344#define dr_flac_c
1345
1346/* Disable some annoying warnings. */
1347#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
1348 #pragma GCC diagnostic push
1349 #if __GNUC__ >= 7
1350 #pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
1351 #endif
1352#endif
1353
1354#ifdef __linux__
1355 #ifndef _BSD_SOURCE
1356 #define _BSD_SOURCE
1357 #endif
1358 #ifndef _DEFAULT_SOURCE
1359 #define _DEFAULT_SOURCE
1360 #endif
1361 #ifndef __USE_BSD
1362 #define __USE_BSD
1363 #endif
1364 #include <endian.h>
1365#endif
1366
1367#include <stdlib.h>
1368#include <string.h>
1369
1370/* Inline */
1371#ifdef _MSC_VER
1372 #define DRFLAC_INLINE __forceinline
1373#elif defined(__GNUC__)
1374 /*
1375 I've had a bug report where GCC is emitting warnings about functions possibly not being inlineable. This warning happens when
1376 the __attribute__((always_inline)) attribute is defined without an "inline" statement. I think therefore there must be some
1377 case where "__inline__" is not always defined, thus the compiler emitting these warnings. When using -std=c89 or -ansi on the
1378 command line, we cannot use the "inline" keyword and instead need to use "__inline__". In an attempt to work around this issue
1379 I am using "__inline__" only when we're compiling in strict ANSI mode.
1380 */
1381 #if defined(__STRICT_ANSI__)
1382 #define DRFLAC_GNUC_INLINE_HINT __inline__
1383 #else
1384 #define DRFLAC_GNUC_INLINE_HINT inline
1385 #endif
1386
1387 #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)) || defined(__clang__)
1388 #define DRFLAC_INLINE DRFLAC_GNUC_INLINE_HINT __attribute__((always_inline))
1389 #else
1390 #define DRFLAC_INLINE DRFLAC_GNUC_INLINE_HINT
1391 #endif
1392#elif defined(__WATCOMC__)
1393 #define DRFLAC_INLINE __inline
1394#else
1395 #define DRFLAC_INLINE
1396#endif
1397/* End Inline */
1398
1399/*
1400Intrinsics Support
1401
1402There's a bug in GCC 4.2.x which results in an incorrect compilation error when using _mm_slli_epi32() where it complains with
1403
1404 "error: shift must be an immediate"
1405
1406Unfortuantely dr_flac depends on this for a few things so we're just going to disable SSE on GCC 4.2 and below.
1407*/
1408#if !defined(DR_FLAC_NO_SIMD)
1409 #if defined(DRFLAC_X64) || defined(DRFLAC_X86)
1410 #if defined(_MSC_VER) && !defined(__clang__)
1411 /* MSVC. */
1412 #if _MSC_VER >= 1400 && !defined(DRFLAC_NO_SSE2) /* 2005 */
1413 #define DRFLAC_SUPPORT_SSE2
1414 #endif
1415 #if _MSC_VER >= 1600 && !defined(DRFLAC_NO_SSE41) /* 2010 */
1416 #define DRFLAC_SUPPORT_SSE41
1417 #endif
1418 #elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
1419 /* Assume GNUC-style. */
1420 #if defined(__SSE2__) && !defined(DRFLAC_NO_SSE2)
1421 #define DRFLAC_SUPPORT_SSE2
1422 #endif
1423 #if defined(__SSE4_1__) && !defined(DRFLAC_NO_SSE41)
1424 #define DRFLAC_SUPPORT_SSE41
1425 #endif
1426 #endif
1427
1428 /* If at this point we still haven't determined compiler support for the intrinsics just fall back to __has_include. */
1429 #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include)
1430 #if !defined(DRFLAC_SUPPORT_SSE2) && !defined(DRFLAC_NO_SSE2) && __has_include(<emmintrin.h>)
1431 #define DRFLAC_SUPPORT_SSE2
1432 #endif
1433 #if !defined(DRFLAC_SUPPORT_SSE41) && !defined(DRFLAC_NO_SSE41) && __has_include(<smmintrin.h>)
1434 #define DRFLAC_SUPPORT_SSE41
1435 #endif
1436 #endif
1437
1438 #if defined(DRFLAC_SUPPORT_SSE41)
1439 #include <smmintrin.h>
1440 #elif defined(DRFLAC_SUPPORT_SSE2)
1441 #include <emmintrin.h>
1442 #endif
1443 #endif
1444
1445 #if defined(DRFLAC_ARM)
1446 #if !defined(DRFLAC_NO_NEON) && (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64))
1447 #define DRFLAC_SUPPORT_NEON
1448 #include <arm_neon.h>
1449 #endif
1450 #endif
1451#endif
1452
1453/* Compile-time CPU feature support. */
1454#if !defined(DR_FLAC_NO_SIMD) && (defined(DRFLAC_X86) || defined(DRFLAC_X64))
1455 #if defined(_MSC_VER) && !defined(__clang__)
1456 #if _MSC_VER >= 1400
1457 #include <intrin.h>
1458 static void drflac__cpuid(int info[4], int fid)
1459 {
1460 __cpuid(info, fid);
1461 }
1462 #else
1463 #define DRFLAC_NO_CPUID
1464 #endif
1465 #else
1466 #if defined(__GNUC__) || defined(__clang__)
1467 static void drflac__cpuid(int info[4], int fid)
1468 {
1469 /*
1470 It looks like the -fPIC option uses the ebx register which GCC complains about. We can work around this by just using a different register, the
1471 specific register of which I'm letting the compiler decide on. The "k" prefix is used to specify a 32-bit register. The {...} syntax is for
1472 supporting different assembly dialects.
1473
1474 What's basically happening is that we're saving and restoring the ebx register manually.
1475 */
1476 #if defined(DRFLAC_X86) && defined(__PIC__)
1477 __asm__ __volatile__ (
1478 "xchg{l} {%%}ebx, %k1;"
1479 "cpuid;"
1480 "xchg{l} {%%}ebx, %k1;"
1481 : "=a"(info[0]), "=&r"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0)
1482 );
1483 #else
1484 __asm__ __volatile__ (
1485 "cpuid" : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0)
1486 );
1487 #endif
1488 }
1489 #else
1490 #define DRFLAC_NO_CPUID
1491 #endif
1492 #endif
1493#else
1494 #define DRFLAC_NO_CPUID
1495#endif
1496
1497static DRFLAC_INLINE drflac_bool32 drflac_has_sse2(void)
1498{
1499#if defined(DRFLAC_SUPPORT_SSE2)
1500 #if (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(DRFLAC_NO_SSE2)
1501 #if defined(DRFLAC_X64)
1502 return DRFLAC_TRUE; /* 64-bit targets always support SSE2. */
1503 #elif (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__)
1504 return DRFLAC_TRUE; /* If the compiler is allowed to freely generate SSE2 code we can assume support. */
1505 #else
1506 #if defined(DRFLAC_NO_CPUID)
1507 return DRFLAC_FALSE;
1508 #else
1509 int info[4];
1510 drflac__cpuid(info, 1);
1511 return (info[3] & (1 << 26)) != 0;
1512 #endif
1513 #endif
1514 #else
1515 return DRFLAC_FALSE; /* SSE2 is only supported on x86 and x64 architectures. */
1516 #endif
1517#else
1518 return DRFLAC_FALSE; /* No compiler support. */
1519#endif
1520}
1521
1522static DRFLAC_INLINE drflac_bool32 drflac_has_sse41(void)
1523{
1524#if defined(DRFLAC_SUPPORT_SSE41)
1525 #if (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(DRFLAC_NO_SSE41)
1526 #if defined(__SSE4_1__) || defined(__AVX__)
1527 return DRFLAC_TRUE; /* If the compiler is allowed to freely generate SSE41 code we can assume support. */
1528 #else
1529 #if defined(DRFLAC_NO_CPUID)
1530 return DRFLAC_FALSE;
1531 #else
1532 int info[4];
1533 drflac__cpuid(info, 1);
1534 return (info[2] & (1 << 19)) != 0;
1535 #endif
1536 #endif
1537 #else
1538 return DRFLAC_FALSE; /* SSE41 is only supported on x86 and x64 architectures. */
1539 #endif
1540#else
1541 return DRFLAC_FALSE; /* No compiler support. */
1542#endif
1543}
1544
1545
1546#if defined(_MSC_VER) && _MSC_VER >= 1500 && (defined(DRFLAC_X86) || defined(DRFLAC_X64)) && !defined(__clang__)
1547 #define DRFLAC_HAS_LZCNT_INTRINSIC
1548#elif (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)))
1549 #define DRFLAC_HAS_LZCNT_INTRINSIC
1550#elif defined(__clang__)
1551 #if defined(__has_builtin)
1552 #if __has_builtin(__builtin_clzll) || __has_builtin(__builtin_clzl)
1553 #define DRFLAC_HAS_LZCNT_INTRINSIC
1554 #endif
1555 #endif
1556#endif
1557
1558#if defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(__clang__)
1559 #define DRFLAC_HAS_BYTESWAP16_INTRINSIC
1560 #define DRFLAC_HAS_BYTESWAP32_INTRINSIC
1561 #define DRFLAC_HAS_BYTESWAP64_INTRINSIC
1562#elif defined(__clang__)
1563 #if defined(__has_builtin)
1564 #if __has_builtin(__builtin_bswap16)
1565 #define DRFLAC_HAS_BYTESWAP16_INTRINSIC
1566 #endif
1567 #if __has_builtin(__builtin_bswap32)
1568 #define DRFLAC_HAS_BYTESWAP32_INTRINSIC
1569 #endif
1570 #if __has_builtin(__builtin_bswap64)
1571 #define DRFLAC_HAS_BYTESWAP64_INTRINSIC
1572 #endif
1573 #endif
1574#elif defined(__GNUC__)
1575 #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
1576 #define DRFLAC_HAS_BYTESWAP32_INTRINSIC
1577 #define DRFLAC_HAS_BYTESWAP64_INTRINSIC
1578 #endif
1579 #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
1580 #define DRFLAC_HAS_BYTESWAP16_INTRINSIC
1581 #endif
1582#elif defined(__WATCOMC__) && defined(__386__)
1583 #define DRFLAC_HAS_BYTESWAP16_INTRINSIC
1584 #define DRFLAC_HAS_BYTESWAP32_INTRINSIC
1585 #define DRFLAC_HAS_BYTESWAP64_INTRINSIC
1586 extern __inline drflac_uint16 _watcom_bswap16(drflac_uint16);
1587 extern __inline drflac_uint32 _watcom_bswap32(drflac_uint32);
1588 extern __inline drflac_uint64 _watcom_bswap64(drflac_uint64);
1589#pragma aux _watcom_bswap16 = \
1590 "xchg al, ah" \
1591 parm [ax] \
1592 value [ax] \
1593 modify nomemory;
1594#pragma aux _watcom_bswap32 = \
1595 "bswap eax" \
1596 parm [eax] \
1597 value [eax] \
1598 modify nomemory;
1599#pragma aux _watcom_bswap64 = \
1600 "bswap eax" \
1601 "bswap edx" \
1602 "xchg eax,edx" \
1603 parm [eax edx] \
1604 value [eax edx] \
1605 modify nomemory;
1606#endif
1607
1608
1609/* Standard library stuff. */
1610#ifndef DRFLAC_ASSERT
1611#include <assert.h>
1612#define DRFLAC_ASSERT(expression) assert(expression)
1613#endif
1614#ifndef DRFLAC_MALLOC
1615#define DRFLAC_MALLOC(sz) malloc((sz))
1616#endif
1617#ifndef DRFLAC_REALLOC
1618#define DRFLAC_REALLOC(p, sz) realloc((p), (sz))
1619#endif
1620#ifndef DRFLAC_FREE
1621#define DRFLAC_FREE(p) free((p))
1622#endif
1623#ifndef DRFLAC_COPY_MEMORY
1624#define DRFLAC_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz))
1625#endif
1626#ifndef DRFLAC_ZERO_MEMORY
1627#define DRFLAC_ZERO_MEMORY(p, sz) memset((p), 0, (sz))
1628#endif
1629#ifndef DRFLAC_ZERO_OBJECT
1630#define DRFLAC_ZERO_OBJECT(p) DRFLAC_ZERO_MEMORY((p), sizeof(*(p)))
1631#endif
1632
1633#define DRFLAC_MAX_SIMD_VECTOR_SIZE 64 /* 64 for AVX-512 in the future. */
1634
1635/* Result Codes */
1636typedef drflac_int32 drflac_result;
1637#define DRFLAC_SUCCESS 0
1638#define DRFLAC_ERROR -1 /* A generic error. */
1639#define DRFLAC_INVALID_ARGS -2
1640#define DRFLAC_INVALID_OPERATION -3
1641#define DRFLAC_OUT_OF_MEMORY -4
1642#define DRFLAC_OUT_OF_RANGE -5
1643#define DRFLAC_ACCESS_DENIED -6
1644#define DRFLAC_DOES_NOT_EXIST -7
1645#define DRFLAC_ALREADY_EXISTS -8
1646#define DRFLAC_TOO_MANY_OPEN_FILES -9
1647#define DRFLAC_INVALID_FILE -10
1648#define DRFLAC_TOO_BIG -11
1649#define DRFLAC_PATH_TOO_LONG -12
1650#define DRFLAC_NAME_TOO_LONG -13
1651#define DRFLAC_NOT_DIRECTORY -14
1652#define DRFLAC_IS_DIRECTORY -15
1653#define DRFLAC_DIRECTORY_NOT_EMPTY -16
1654#define DRFLAC_END_OF_FILE -17
1655#define DRFLAC_NO_SPACE -18
1656#define DRFLAC_BUSY -19
1657#define DRFLAC_IO_ERROR -20
1658#define DRFLAC_INTERRUPT -21
1659#define DRFLAC_UNAVAILABLE -22
1660#define DRFLAC_ALREADY_IN_USE -23
1661#define DRFLAC_BAD_ADDRESS -24
1662#define DRFLAC_BAD_SEEK -25
1663#define DRFLAC_BAD_PIPE -26
1664#define DRFLAC_DEADLOCK -27
1665#define DRFLAC_TOO_MANY_LINKS -28
1666#define DRFLAC_NOT_IMPLEMENTED -29
1667#define DRFLAC_NO_MESSAGE -30
1668#define DRFLAC_BAD_MESSAGE -31
1669#define DRFLAC_NO_DATA_AVAILABLE -32
1670#define DRFLAC_INVALID_DATA -33
1671#define DRFLAC_TIMEOUT -34
1672#define DRFLAC_NO_NETWORK -35
1673#define DRFLAC_NOT_UNIQUE -36
1674#define DRFLAC_NOT_SOCKET -37
1675#define DRFLAC_NO_ADDRESS -38
1676#define DRFLAC_BAD_PROTOCOL -39
1677#define DRFLAC_PROTOCOL_UNAVAILABLE -40
1678#define DRFLAC_PROTOCOL_NOT_SUPPORTED -41
1679#define DRFLAC_PROTOCOL_FAMILY_NOT_SUPPORTED -42
1680#define DRFLAC_ADDRESS_FAMILY_NOT_SUPPORTED -43
1681#define DRFLAC_SOCKET_NOT_SUPPORTED -44
1682#define DRFLAC_CONNECTION_RESET -45
1683#define DRFLAC_ALREADY_CONNECTED -46
1684#define DRFLAC_NOT_CONNECTED -47
1685#define DRFLAC_CONNECTION_REFUSED -48
1686#define DRFLAC_NO_HOST -49
1687#define DRFLAC_IN_PROGRESS -50
1688#define DRFLAC_CANCELLED -51
1689#define DRFLAC_MEMORY_ALREADY_MAPPED -52
1690#define DRFLAC_AT_END -53
1691
1692#define DRFLAC_CRC_MISMATCH -100
1693/* End Result Codes */
1694
1695
1696#define DRFLAC_SUBFRAME_CONSTANT 0
1697#define DRFLAC_SUBFRAME_VERBATIM 1
1698#define DRFLAC_SUBFRAME_FIXED 8
1699#define DRFLAC_SUBFRAME_LPC 32
1700#define DRFLAC_SUBFRAME_RESERVED 255
1701
1702#define DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE 0
1703#define DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2 1
1704
1705#define DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT 0
1706#define DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE 8
1707#define DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE 9
1708#define DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE 10
1709
1710#define DRFLAC_SEEKPOINT_SIZE_IN_BYTES 18
1711#define DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES 36
1712#define DRFLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES 12
1713
1714#define drflac_align(x, a) ((((x) + (a) - 1) / (a)) * (a))
1715
1716
1717DRFLAC_API void drflac_version(drflac_uint32* pMajor, drflac_uint32* pMinor, drflac_uint32* pRevision)
1718{
1719 if (pMajor) {
1720 *pMajor = DRFLAC_VERSION_MAJOR;
1721 }
1722
1723 if (pMinor) {
1724 *pMinor = DRFLAC_VERSION_MINOR;
1725 }
1726
1727 if (pRevision) {
1728 *pRevision = DRFLAC_VERSION_REVISION;
1729 }
1730}
1731
1732DRFLAC_API const char* drflac_version_string(void)
1733{
1734 return DRFLAC_VERSION_STRING;
1735}
1736
1737
1738/* CPU caps. */
1739#if defined(__has_feature)
1740 #if __has_feature(thread_sanitizer)
1741 #define DRFLAC_NO_THREAD_SANITIZE __attribute__((no_sanitize("thread")))
1742 #else
1743 #define DRFLAC_NO_THREAD_SANITIZE
1744 #endif
1745#else
1746 #define DRFLAC_NO_THREAD_SANITIZE
1747#endif
1748
1749#if defined(DRFLAC_HAS_LZCNT_INTRINSIC)
1750static drflac_bool32 drflac__gIsLZCNTSupported = DRFLAC_FALSE;
1751#endif
1752
1753#ifndef DRFLAC_NO_CPUID
1754static drflac_bool32 drflac__gIsSSE2Supported = DRFLAC_FALSE;
1755static drflac_bool32 drflac__gIsSSE41Supported = DRFLAC_FALSE;
1756
1757/*
1758I've had a bug report that Clang's ThreadSanitizer presents a warning in this function. Having reviewed this, this does
1759actually make sense. However, since CPU caps should never differ for a running process, I don't think the trade off of
1760complicating internal API's by passing around CPU caps versus just disabling the warnings is worthwhile. I'm therefore
1761just going to disable these warnings. This is disabled via the DRFLAC_NO_THREAD_SANITIZE attribute.
1762*/
1763DRFLAC_NO_THREAD_SANITIZE static void drflac__init_cpu_caps(void)
1764{
1765 static drflac_bool32 isCPUCapsInitialized = DRFLAC_FALSE;
1766
1767 if (!isCPUCapsInitialized) {
1768 /* LZCNT */
1769#if defined(DRFLAC_HAS_LZCNT_INTRINSIC)
1770 int info[4] = {0};
1771 drflac__cpuid(info, 0x80000001);
1772 drflac__gIsLZCNTSupported = (info[2] & (1 << 5)) != 0;
1773#endif
1774
1775 /* SSE2 */
1776 drflac__gIsSSE2Supported = drflac_has_sse2();
1777
1778 /* SSE4.1 */
1779 drflac__gIsSSE41Supported = drflac_has_sse41();
1780
1781 /* Initialized. */
1782 isCPUCapsInitialized = DRFLAC_TRUE;
1783 }
1784}
1785#else
1786static drflac_bool32 drflac__gIsNEONSupported = DRFLAC_FALSE;
1787
1788static DRFLAC_INLINE drflac_bool32 drflac__has_neon(void)
1789{
1790#if defined(DRFLAC_SUPPORT_NEON)
1791 #if defined(DRFLAC_ARM) && !defined(DRFLAC_NO_NEON)
1792 #if (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64))
1793 return DRFLAC_TRUE; /* If the compiler is allowed to freely generate NEON code we can assume support. */
1794 #else
1795 /* TODO: Runtime check. */
1796 return DRFLAC_FALSE;
1797 #endif
1798 #else
1799 return DRFLAC_FALSE; /* NEON is only supported on ARM architectures. */
1800 #endif
1801#else
1802 return DRFLAC_FALSE; /* No compiler support. */
1803#endif
1804}
1805
1806DRFLAC_NO_THREAD_SANITIZE static void drflac__init_cpu_caps(void)
1807{
1808 drflac__gIsNEONSupported = drflac__has_neon();
1809
1810#if defined(DRFLAC_HAS_LZCNT_INTRINSIC) && defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5)
1811 drflac__gIsLZCNTSupported = DRFLAC_TRUE;
1812#endif
1813}
1814#endif
1815
1816
1817/* Endian Management */
1818static DRFLAC_INLINE drflac_bool32 drflac__is_little_endian(void)
1819{
1820#if defined(DRFLAC_X86) || defined(DRFLAC_X64)
1821 return DRFLAC_TRUE;
1822#elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN
1823 return DRFLAC_TRUE;
1824#else
1825 int n = 1;
1826 return (*(char*)&n) == 1;
1827#endif
1828}
1829
1830static DRFLAC_INLINE drflac_uint16 drflac__swap_endian_uint16(drflac_uint16 n)
1831{
1832#ifdef DRFLAC_HAS_BYTESWAP16_INTRINSIC
1833 #if defined(_MSC_VER) && !defined(__clang__)
1834 return _byteswap_ushort(n);
1835 #elif defined(__GNUC__) || defined(__clang__)
1836 return __builtin_bswap16(n);
1837 #elif defined(__WATCOMC__) && defined(__386__)
1838 return _watcom_bswap16(n);
1839 #else
1840 #error "This compiler does not support the byte swap intrinsic."
1841 #endif
1842#else
1843 return ((n & 0xFF00) >> 8) |
1844 ((n & 0x00FF) << 8);
1845#endif
1846}
1847
1848static DRFLAC_INLINE drflac_uint32 drflac__swap_endian_uint32(drflac_uint32 n)
1849{
1850#ifdef DRFLAC_HAS_BYTESWAP32_INTRINSIC
1851 #if defined(_MSC_VER) && !defined(__clang__)
1852 return _byteswap_ulong(n);
1853 #elif defined(__GNUC__) || defined(__clang__)
1854 #if defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(__ARM_ARCH_6M__) && !defined(DRFLAC_64BIT) /* <-- 64-bit inline assembly has not been tested, so disabling for now. */
1855 /* Inline assembly optimized implementation for ARM. In my testing, GCC does not generate optimized code with __builtin_bswap32(). */
1856 drflac_uint32 r;
1857 __asm__ __volatile__ (
1858 #if defined(DRFLAC_64BIT)
1859 "rev %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(n) /* <-- This is untested. If someone in the community could test this, that would be appreciated! */
1860 #else
1861 "rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n)
1862 #endif
1863 );
1864 return r;
1865 #else
1866 return __builtin_bswap32(n);
1867 #endif
1868 #elif defined(__WATCOMC__) && defined(__386__)
1869 return _watcom_bswap32(n);
1870 #else
1871 #error "This compiler does not support the byte swap intrinsic."
1872 #endif
1873#else
1874 return ((n & 0xFF000000) >> 24) |
1875 ((n & 0x00FF0000) >> 8) |
1876 ((n & 0x0000FF00) << 8) |
1877 ((n & 0x000000FF) << 24);
1878#endif
1879}
1880
1881static DRFLAC_INLINE drflac_uint64 drflac__swap_endian_uint64(drflac_uint64 n)
1882{
1883#ifdef DRFLAC_HAS_BYTESWAP64_INTRINSIC
1884 #if defined(_MSC_VER) && !defined(__clang__)
1885 return _byteswap_uint64(n);
1886 #elif defined(__GNUC__) || defined(__clang__)
1887 return __builtin_bswap64(n);
1888 #elif defined(__WATCOMC__) && defined(__386__)
1889 return _watcom_bswap64(n);
1890 #else
1891 #error "This compiler does not support the byte swap intrinsic."
1892 #endif
1893#else
1894 /* Weird "<< 32" bitshift is required for C89 because it doesn't support 64-bit constants. Should be optimized out by a good compiler. */
1895 return ((n & ((drflac_uint64)0xFF000000 << 32)) >> 56) |
1896 ((n & ((drflac_uint64)0x00FF0000 << 32)) >> 40) |
1897 ((n & ((drflac_uint64)0x0000FF00 << 32)) >> 24) |
1898 ((n & ((drflac_uint64)0x000000FF << 32)) >> 8) |
1899 ((n & ((drflac_uint64)0xFF000000 )) << 8) |
1900 ((n & ((drflac_uint64)0x00FF0000 )) << 24) |
1901 ((n & ((drflac_uint64)0x0000FF00 )) << 40) |
1902 ((n & ((drflac_uint64)0x000000FF )) << 56);
1903#endif
1904}
1905
1906
1907static DRFLAC_INLINE drflac_uint16 drflac__be2host_16(drflac_uint16 n)
1908{
1909 if (drflac__is_little_endian()) {
1910 return drflac__swap_endian_uint16(n);
1911 }
1912
1913 return n;
1914}
1915
1916static DRFLAC_INLINE drflac_uint32 drflac__be2host_32(drflac_uint32 n)
1917{
1918 if (drflac__is_little_endian()) {
1919 return drflac__swap_endian_uint32(n);
1920 }
1921
1922 return n;
1923}
1924
1925static DRFLAC_INLINE drflac_uint32 drflac__be2host_32_ptr_unaligned(const void* pData)
1926{
1927 const drflac_uint8* pNum = (drflac_uint8*)pData;
1928 return *(pNum) << 24 | *(pNum+1) << 16 | *(pNum+2) << 8 | *(pNum+3);
1929}
1930
1931static DRFLAC_INLINE drflac_uint64 drflac__be2host_64(drflac_uint64 n)
1932{
1933 if (drflac__is_little_endian()) {
1934 return drflac__swap_endian_uint64(n);
1935 }
1936
1937 return n;
1938}
1939
1940
1941static DRFLAC_INLINE drflac_uint32 drflac__le2host_32(drflac_uint32 n)
1942{
1943 if (!drflac__is_little_endian()) {
1944 return drflac__swap_endian_uint32(n);
1945 }
1946
1947 return n;
1948}
1949
1950static DRFLAC_INLINE drflac_uint32 drflac__le2host_32_ptr_unaligned(const void* pData)
1951{
1952 const drflac_uint8* pNum = (drflac_uint8*)pData;
1953 return *pNum | *(pNum+1) << 8 | *(pNum+2) << 16 | *(pNum+3) << 24;
1954}
1955
1956
1957static DRFLAC_INLINE drflac_uint32 drflac__unsynchsafe_32(drflac_uint32 n)
1958{
1959 drflac_uint32 result = 0;
1960 result |= (n & 0x7F000000) >> 3;
1961 result |= (n & 0x007F0000) >> 2;
1962 result |= (n & 0x00007F00) >> 1;
1963 result |= (n & 0x0000007F) >> 0;
1964
1965 return result;
1966}
1967
1968
1969
1970/* The CRC code below is based on this document: http://zlib.net/crc_v3.txt */
1971static drflac_uint8 drflac__crc8_table[] = {
1972 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
1973 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
1974 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
1975 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
1976 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
1977 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
1978 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
1979 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
1980 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
1981 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
1982 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
1983 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
1984 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
1985 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
1986 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
1987 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
1988};
1989
1990static drflac_uint16 drflac__crc16_table[] = {
1991 0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011,
1992 0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022,
1993 0x8063, 0x0066, 0x006C, 0x8069, 0x0078, 0x807D, 0x8077, 0x0072,
1994 0x0050, 0x8055, 0x805F, 0x005A, 0x804B, 0x004E, 0x0044, 0x8041,
1995 0x80C3, 0x00C6, 0x00CC, 0x80C9, 0x00D8, 0x80DD, 0x80D7, 0x00D2,
1996 0x00F0, 0x80F5, 0x80FF, 0x00FA, 0x80EB, 0x00EE, 0x00E4, 0x80E1,
1997 0x00A0, 0x80A5, 0x80AF, 0x00AA, 0x80BB, 0x00BE, 0x00B4, 0x80B1,
1998 0x8093, 0x0096, 0x009C, 0x8099, 0x0088, 0x808D, 0x8087, 0x0082,
1999 0x8183, 0x0186, 0x018C, 0x8189, 0x0198, 0x819D, 0x8197, 0x0192,
2000 0x01B0, 0x81B5, 0x81BF, 0x01BA, 0x81AB, 0x01AE, 0x01A4, 0x81A1,
2001 0x01E0, 0x81E5, 0x81EF, 0x01EA, 0x81FB, 0x01FE, 0x01F4, 0x81F1,
2002 0x81D3, 0x01D6, 0x01DC, 0x81D9, 0x01C8, 0x81CD, 0x81C7, 0x01C2,
2003 0x0140, 0x8145, 0x814F, 0x014A, 0x815B, 0x015E, 0x0154, 0x8151,
2004 0x8173, 0x0176, 0x017C, 0x8179, 0x0168, 0x816D, 0x8167, 0x0162,
2005 0x8123, 0x0126, 0x012C, 0x8129, 0x0138, 0x813D, 0x8137, 0x0132,
2006 0x0110, 0x8115, 0x811F, 0x011A, 0x810B, 0x010E, 0x0104, 0x8101,
2007 0x8303, 0x0306, 0x030C, 0x8309, 0x0318, 0x831D, 0x8317, 0x0312,
2008 0x0330, 0x8335, 0x833F, 0x033A, 0x832B, 0x032E, 0x0324, 0x8321,
2009 0x0360, 0x8365, 0x836F, 0x036A, 0x837B, 0x037E, 0x0374, 0x8371,
2010 0x8353, 0x0356, 0x035C, 0x8359, 0x0348, 0x834D, 0x8347, 0x0342,
2011 0x03C0, 0x83C5, 0x83CF, 0x03CA, 0x83DB, 0x03DE, 0x03D4, 0x83D1,
2012 0x83F3, 0x03F6, 0x03FC, 0x83F9, 0x03E8, 0x83ED, 0x83E7, 0x03E2,
2013 0x83A3, 0x03A6, 0x03AC, 0x83A9, 0x03B8, 0x83BD, 0x83B7, 0x03B2,
2014 0x0390, 0x8395, 0x839F, 0x039A, 0x838B, 0x038E, 0x0384, 0x8381,
2015 0x0280, 0x8285, 0x828F, 0x028A, 0x829B, 0x029E, 0x0294, 0x8291,
2016 0x82B3, 0x02B6, 0x02BC, 0x82B9, 0x02A8, 0x82AD, 0x82A7, 0x02A2,
2017 0x82E3, 0x02E6, 0x02EC, 0x82E9, 0x02F8, 0x82FD, 0x82F7, 0x02F2,
2018 0x02D0, 0x82D5, 0x82DF, 0x02DA, 0x82CB, 0x02CE, 0x02C4, 0x82C1,
2019 0x8243, 0x0246, 0x024C, 0x8249, 0x0258, 0x825D, 0x8257, 0x0252,
2020 0x0270, 0x8275, 0x827F, 0x027A, 0x826B, 0x026E, 0x0264, 0x8261,
2021 0x0220, 0x8225, 0x822F, 0x022A, 0x823B, 0x023E, 0x0234, 0x8231,
2022 0x8213, 0x0216, 0x021C, 0x8219, 0x0208, 0x820D, 0x8207, 0x0202
2023};
2024
2025static DRFLAC_INLINE drflac_uint8 drflac_crc8_byte(drflac_uint8 crc, drflac_uint8 data)
2026{
2027 return drflac__crc8_table[crc ^ data];
2028}
2029
2030static DRFLAC_INLINE drflac_uint8 drflac_crc8(drflac_uint8 crc, drflac_uint32 data, drflac_uint32 count)
2031{
2032#ifdef DR_FLAC_NO_CRC
2033 (void)crc;
2034 (void)data;
2035 (void)count;
2036 return 0;
2037#else
2038#if 0
2039 /* REFERENCE (use of this implementation requires an explicit flush by doing "drflac_crc8(crc, 0, 8);") */
2040 drflac_uint8 p = 0x07;
2041 for (int i = count-1; i >= 0; --i) {
2042 drflac_uint8 bit = (data & (1 << i)) >> i;
2043 if (crc & 0x80) {
2044 crc = ((crc << 1) | bit) ^ p;
2045 } else {
2046 crc = ((crc << 1) | bit);
2047 }
2048 }
2049 return crc;
2050#else
2051 drflac_uint32 wholeBytes;
2052 drflac_uint32 leftoverBits;
2053 drflac_uint64 leftoverDataMask;
2054
2055 static drflac_uint64 leftoverDataMaskTable[8] = {
2056 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F
2057 };
2058
2059 DRFLAC_ASSERT(count <= 32);
2060
2061 wholeBytes = count >> 3;
2062 leftoverBits = count - (wholeBytes*8);
2063 leftoverDataMask = leftoverDataMaskTable[leftoverBits];
2064
2065 switch (wholeBytes) {
2066 case 4: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0xFF000000UL << leftoverBits)) >> (24 + leftoverBits)));
2067 case 3: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0x00FF0000UL << leftoverBits)) >> (16 + leftoverBits)));
2068 case 2: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0x0000FF00UL << leftoverBits)) >> ( 8 + leftoverBits)));
2069 case 1: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0x000000FFUL << leftoverBits)) >> ( 0 + leftoverBits)));
2070 case 0: if (leftoverBits > 0) crc = (drflac_uint8)((crc << leftoverBits) ^ drflac__crc8_table[(crc >> (8 - leftoverBits)) ^ (data & leftoverDataMask)]);
2071 }
2072 return crc;
2073#endif
2074#endif
2075}
2076
2077static DRFLAC_INLINE drflac_uint16 drflac_crc16_byte(drflac_uint16 crc, drflac_uint8 data)
2078{
2079 return (crc << 8) ^ drflac__crc16_table[(drflac_uint8)(crc >> 8) ^ data];
2080}
2081
2082static DRFLAC_INLINE drflac_uint16 drflac_crc16_cache(drflac_uint16 crc, drflac_cache_t data)
2083{
2084#ifdef DRFLAC_64BIT
2085 crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 56) & 0xFF));
2086 crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 48) & 0xFF));
2087 crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 40) & 0xFF));
2088 crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 32) & 0xFF));
2089#endif
2090 crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 24) & 0xFF));
2091 crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 16) & 0xFF));
2092 crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 8) & 0xFF));
2093 crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 0) & 0xFF));
2094
2095 return crc;
2096}
2097
2098static DRFLAC_INLINE drflac_uint16 drflac_crc16_bytes(drflac_uint16 crc, drflac_cache_t data, drflac_uint32 byteCount)
2099{
2100 switch (byteCount)
2101 {
2102#ifdef DRFLAC_64BIT
2103 case 8: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 56) & 0xFF));
2104 case 7: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 48) & 0xFF));
2105 case 6: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 40) & 0xFF));
2106 case 5: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 32) & 0xFF));
2107#endif
2108 case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 24) & 0xFF));
2109 case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 16) & 0xFF));
2110 case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 8) & 0xFF));
2111 case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 0) & 0xFF));
2112 }
2113
2114 return crc;
2115}
2116
2117#if 0
2118static DRFLAC_INLINE drflac_uint16 drflac_crc16__32bit(drflac_uint16 crc, drflac_uint32 data, drflac_uint32 count)
2119{
2120#ifdef DR_FLAC_NO_CRC
2121 (void)crc;
2122 (void)data;
2123 (void)count;
2124 return 0;
2125#else
2126#if 0
2127 /* REFERENCE (use of this implementation requires an explicit flush by doing "drflac_crc16(crc, 0, 16);") */
2128 drflac_uint16 p = 0x8005;
2129 for (int i = count-1; i >= 0; --i) {
2130 drflac_uint16 bit = (data & (1ULL << i)) >> i;
2131 if (r & 0x8000) {
2132 r = ((r << 1) | bit) ^ p;
2133 } else {
2134 r = ((r << 1) | bit);
2135 }
2136 }
2137
2138 return crc;
2139#else
2140 drflac_uint32 wholeBytes;
2141 drflac_uint32 leftoverBits;
2142 drflac_uint64 leftoverDataMask;
2143
2144 static drflac_uint64 leftoverDataMaskTable[8] = {
2145 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F
2146 };
2147
2148 DRFLAC_ASSERT(count <= 64);
2149
2150 wholeBytes = count >> 3;
2151 leftoverBits = count & 7;
2152 leftoverDataMask = leftoverDataMaskTable[leftoverBits];
2153
2154 switch (wholeBytes) {
2155 default:
2156 case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0xFF000000UL << leftoverBits)) >> (24 + leftoverBits)));
2157 case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0x00FF0000UL << leftoverBits)) >> (16 + leftoverBits)));
2158 case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0x0000FF00UL << leftoverBits)) >> ( 8 + leftoverBits)));
2159 case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0x000000FFUL << leftoverBits)) >> ( 0 + leftoverBits)));
2160 case 0: if (leftoverBits > 0) crc = (crc << leftoverBits) ^ drflac__crc16_table[(crc >> (16 - leftoverBits)) ^ (data & leftoverDataMask)];
2161 }
2162 return crc;
2163#endif
2164#endif
2165}
2166
2167static DRFLAC_INLINE drflac_uint16 drflac_crc16__64bit(drflac_uint16 crc, drflac_uint64 data, drflac_uint32 count)
2168{
2169#ifdef DR_FLAC_NO_CRC
2170 (void)crc;
2171 (void)data;
2172 (void)count;
2173 return 0;
2174#else
2175 drflac_uint32 wholeBytes;
2176 drflac_uint32 leftoverBits;
2177 drflac_uint64 leftoverDataMask;
2178
2179 static drflac_uint64 leftoverDataMaskTable[8] = {
2180 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F
2181 };
2182
2183 DRFLAC_ASSERT(count <= 64);
2184
2185 wholeBytes = count >> 3;
2186 leftoverBits = count & 7;
2187 leftoverDataMask = leftoverDataMaskTable[leftoverBits];
2188
2189 switch (wholeBytes) {
2190 default:
2191 case 8: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0xFF000000 << 32) << leftoverBits)) >> (56 + leftoverBits))); /* Weird "<< 32" bitshift is required for C89 because it doesn't support 64-bit constants. Should be optimized out by a good compiler. */
2192 case 7: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x00FF0000 << 32) << leftoverBits)) >> (48 + leftoverBits)));
2193 case 6: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x0000FF00 << 32) << leftoverBits)) >> (40 + leftoverBits)));
2194 case 5: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x000000FF << 32) << leftoverBits)) >> (32 + leftoverBits)));
2195 case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0xFF000000 ) << leftoverBits)) >> (24 + leftoverBits)));
2196 case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x00FF0000 ) << leftoverBits)) >> (16 + leftoverBits)));
2197 case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x0000FF00 ) << leftoverBits)) >> ( 8 + leftoverBits)));
2198 case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x000000FF ) << leftoverBits)) >> ( 0 + leftoverBits)));
2199 case 0: if (leftoverBits > 0) crc = (crc << leftoverBits) ^ drflac__crc16_table[(crc >> (16 - leftoverBits)) ^ (data & leftoverDataMask)];
2200 }
2201 return crc;
2202#endif
2203}
2204
2205
2206static DRFLAC_INLINE drflac_uint16 drflac_crc16(drflac_uint16 crc, drflac_cache_t data, drflac_uint32 count)
2207{
2208#ifdef DRFLAC_64BIT
2209 return drflac_crc16__64bit(crc, data, count);
2210#else
2211 return drflac_crc16__32bit(crc, data, count);
2212#endif
2213}
2214#endif
2215
2216
2217#ifdef DRFLAC_64BIT
2218#define drflac__be2host__cache_line drflac__be2host_64
2219#else
2220#define drflac__be2host__cache_line drflac__be2host_32
2221#endif
2222
2223/*
2224BIT READING ATTEMPT #2
2225
2226This 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
2227on the most significant bit. It uses the notion of an L1 and L2 cache (borrowed from CPU architecture), where the L1 cache
2228is 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
2229array 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
2230from onRead() is read into.
2231*/
2232#define DRFLAC_CACHE_L1_SIZE_BYTES(bs) (sizeof((bs)->cache))
2233#define DRFLAC_CACHE_L1_SIZE_BITS(bs) (sizeof((bs)->cache)*8)
2234#define DRFLAC_CACHE_L1_BITS_REMAINING(bs) (DRFLAC_CACHE_L1_SIZE_BITS(bs) - (bs)->consumedBits)
2235#define DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount) (~((~(drflac_cache_t)0) >> (_bitCount)))
2236#define DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, _bitCount) (DRFLAC_CACHE_L1_SIZE_BITS(bs) - (_bitCount))
2237#define DRFLAC_CACHE_L1_SELECT(bs, _bitCount) (((bs)->cache) & DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount))
2238#define DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, _bitCount) (DRFLAC_CACHE_L1_SELECT((bs), (_bitCount)) >> DRFLAC_CACHE_L1_SELECTION_SHIFT((bs), (_bitCount)))
2239#define DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE(bs, _bitCount)(DRFLAC_CACHE_L1_SELECT((bs), (_bitCount)) >> (DRFLAC_CACHE_L1_SELECTION_SHIFT((bs), (_bitCount)) & (DRFLAC_CACHE_L1_SIZE_BITS(bs)-1)))
2240#define DRFLAC_CACHE_L2_SIZE_BYTES(bs) (sizeof((bs)->cacheL2))
2241#define DRFLAC_CACHE_L2_LINE_COUNT(bs) (DRFLAC_CACHE_L2_SIZE_BYTES(bs) / sizeof((bs)->cacheL2[0]))
2242#define DRFLAC_CACHE_L2_LINES_REMAINING(bs) (DRFLAC_CACHE_L2_LINE_COUNT(bs) - (bs)->nextL2Line)
2243
2244
2245#ifndef DR_FLAC_NO_CRC
2246static DRFLAC_INLINE void drflac__reset_crc16(drflac_bs* bs)
2247{
2248 bs->crc16 = 0;
2249 bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3;
2250}
2251
2252static DRFLAC_INLINE void drflac__update_crc16(drflac_bs* bs)
2253{
2254 if (bs->crc16CacheIgnoredBytes == 0) {
2255 bs->crc16 = drflac_crc16_cache(bs->crc16, bs->crc16Cache);
2256 } else {
2257 bs->crc16 = drflac_crc16_bytes(bs->crc16, bs->crc16Cache, DRFLAC_CACHE_L1_SIZE_BYTES(bs) - bs->crc16CacheIgnoredBytes);
2258 bs->crc16CacheIgnoredBytes = 0;
2259 }
2260}
2261
2262static DRFLAC_INLINE drflac_uint16 drflac__flush_crc16(drflac_bs* bs)
2263{
2264 /* We should never be flushing in a situation where we are not aligned on a byte boundary. */
2265 DRFLAC_ASSERT((DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7) == 0);
2266
2267 /*
2268 The bits that were read from the L1 cache need to be accumulated. The number of bytes needing to be accumulated is determined
2269 by the number of bits that have been consumed.
2270 */
2271 if (DRFLAC_CACHE_L1_BITS_REMAINING(bs) == 0) {
2272 drflac__update_crc16(bs);
2273 } else {
2274 /* We only accumulate the consumed bits. */
2275 bs->crc16 = drflac_crc16_bytes(bs->crc16, bs->crc16Cache >> DRFLAC_CACHE_L1_BITS_REMAINING(bs), (bs->consumedBits >> 3) - bs->crc16CacheIgnoredBytes);
2276
2277 /*
2278 The bits that we just accumulated should never be accumulated again. We need to keep track of how many bytes were accumulated
2279 so we can handle that later.
2280 */
2281 bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3;
2282 }
2283
2284 return bs->crc16;
2285}
2286#endif
2287
2288static DRFLAC_INLINE drflac_bool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs)
2289{
2290 size_t bytesRead;
2291 size_t alignedL1LineCount;
2292
2293 /* Fast path. Try loading straight from L2. */
2294 if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
2295 bs->cache = bs->cacheL2[bs->nextL2Line++];
2296 return DRFLAC_TRUE;
2297 }
2298
2299 /*
2300 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
2301 any left.
2302 */
2303 if (bs->unalignedByteCount > 0) {
2304 return DRFLAC_FALSE; /* If we have any unaligned bytes it means there's no more aligned bytes left in the client. */
2305 }
2306
2307 bytesRead = bs->onRead(bs->pUserData, bs->cacheL2, DRFLAC_CACHE_L2_SIZE_BYTES(bs));
2308
2309 bs->nextL2Line = 0;
2310 if (bytesRead == DRFLAC_CACHE_L2_SIZE_BYTES(bs)) {
2311 bs->cache = bs->cacheL2[bs->nextL2Line++];
2312 return DRFLAC_TRUE;
2313 }
2314
2315
2316 /*
2317 If we get here it means we were unable to retrieve enough data to fill the entire L2 cache. It probably
2318 means we've just reached the end of the file. We need to move the valid data down to the end of the buffer
2319 and adjust the index of the next line accordingly. Also keep in mind that the L2 cache must be aligned to
2320 the size of the L1 so we'll need to seek backwards by any misaligned bytes.
2321 */
2322 alignedL1LineCount = bytesRead / DRFLAC_CACHE_L1_SIZE_BYTES(bs);
2323
2324 /* We need to keep track of any unaligned bytes for later use. */
2325 bs->unalignedByteCount = bytesRead - (alignedL1LineCount * DRFLAC_CACHE_L1_SIZE_BYTES(bs));
2326 if (bs->unalignedByteCount > 0) {
2327 bs->unalignedCache = bs->cacheL2[alignedL1LineCount];
2328 }
2329
2330 if (alignedL1LineCount > 0) {
2331 size_t offset = DRFLAC_CACHE_L2_LINE_COUNT(bs) - alignedL1LineCount;
2332 size_t i;
2333 for (i = alignedL1LineCount; i > 0; --i) {
2334 bs->cacheL2[i-1 + offset] = bs->cacheL2[i-1];
2335 }
2336
2337 bs->nextL2Line = (drflac_uint32)offset;
2338 bs->cache = bs->cacheL2[bs->nextL2Line++];
2339 return DRFLAC_TRUE;
2340 } else {
2341 /* If we get into this branch it means we weren't able to load any L1-aligned data. */
2342 bs->nextL2Line = DRFLAC_CACHE_L2_LINE_COUNT(bs);
2343 return DRFLAC_FALSE;
2344 }
2345}
2346
2347static drflac_bool32 drflac__reload_cache(drflac_bs* bs)
2348{
2349 size_t bytesRead;
2350
2351#ifndef DR_FLAC_NO_CRC
2352 drflac__update_crc16(bs);
2353#endif
2354
2355 /* Fast path. Try just moving the next value in the L2 cache to the L1 cache. */
2356 if (drflac__reload_l1_cache_from_l2(bs)) {
2357 bs->cache = drflac__be2host__cache_line(bs->cache);
2358 bs->consumedBits = 0;
2359#ifndef DR_FLAC_NO_CRC
2360 bs->crc16Cache = bs->cache;
2361#endif
2362 return DRFLAC_TRUE;
2363 }
2364
2365 /* Slow path. */
2366
2367 /*
2368 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
2369 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
2370 data from the unaligned cache.
2371 */
2372 bytesRead = bs->unalignedByteCount;
2373 if (bytesRead == 0) {
2374 bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs); /* <-- The stream has been exhausted, so marked the bits as consumed. */
2375 return DRFLAC_FALSE;
2376 }
2377
2378 DRFLAC_ASSERT(bytesRead < DRFLAC_CACHE_L1_SIZE_BYTES(bs));
2379 bs->consumedBits = (drflac_uint32)(DRFLAC_CACHE_L1_SIZE_BYTES(bs) - bytesRead) * 8;
2380
2381 bs->cache = drflac__be2host__cache_line(bs->unalignedCache);
2382 bs->cache &= DRFLAC_CACHE_L1_SELECTION_MASK(DRFLAC_CACHE_L1_BITS_REMAINING(bs)); /* <-- Make sure the consumed bits are always set to zero. Other parts of the library depend on this property. */
2383 bs->unalignedByteCount = 0; /* <-- At this point the unaligned bytes have been moved into the cache and we thus have no more unaligned bytes. */
2384
2385#ifndef DR_FLAC_NO_CRC
2386 bs->crc16Cache = bs->cache >> bs->consumedBits;
2387 bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3;
2388#endif
2389 return DRFLAC_TRUE;
2390}
2391
2392static void drflac__reset_cache(drflac_bs* bs)
2393{
2394 bs->nextL2Line = DRFLAC_CACHE_L2_LINE_COUNT(bs); /* <-- This clears the L2 cache. */
2395 bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs); /* <-- This clears the L1 cache. */
2396 bs->cache = 0;
2397 bs->unalignedByteCount = 0; /* <-- This clears the trailing unaligned bytes. */
2398 bs->unalignedCache = 0;
2399
2400#ifndef DR_FLAC_NO_CRC
2401 bs->crc16Cache = 0;
2402 bs->crc16CacheIgnoredBytes = 0;
2403#endif
2404}
2405
2406
2407static DRFLAC_INLINE drflac_bool32 drflac__read_uint32(drflac_bs* bs, unsigned int bitCount, drflac_uint32* pResultOut)
2408{
2409 DRFLAC_ASSERT(bs != NULL);
2410 DRFLAC_ASSERT(pResultOut != NULL);
2411 DRFLAC_ASSERT(bitCount > 0);
2412 DRFLAC_ASSERT(bitCount <= 32);
2413
2414 if (bs->consumedBits == DRFLAC_CACHE_L1_SIZE_BITS(bs)) {
2415 if (!drflac__reload_cache(bs)) {
2416 return DRFLAC_FALSE;
2417 }
2418 }
2419
2420 if (bitCount <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
2421 /*
2422 If we want to load all 32-bits from a 32-bit cache we need to do it slightly differently because we can't do
2423 a 32-bit shift on a 32-bit integer. This will never be the case on 64-bit caches, so we can have a slightly
2424 more optimal solution for this.
2425 */
2426#ifdef DRFLAC_64BIT
2427 *pResultOut = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCount);
2428 bs->consumedBits += bitCount;
2429 bs->cache <<= bitCount;
2430#else
2431 if (bitCount < DRFLAC_CACHE_L1_SIZE_BITS(bs)) {
2432 *pResultOut = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCount);
2433 bs->consumedBits += bitCount;
2434 bs->cache <<= bitCount;
2435 } else {
2436 /* Cannot shift by 32-bits, so need to do it differently. */
2437 *pResultOut = (drflac_uint32)bs->cache;
2438 bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs);
2439 bs->cache = 0;
2440 }
2441#endif
2442
2443 return DRFLAC_TRUE;
2444 } else {
2445 /* 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. */
2446 drflac_uint32 bitCountHi = DRFLAC_CACHE_L1_BITS_REMAINING(bs);
2447 drflac_uint32 bitCountLo = bitCount - bitCountHi;
2448 drflac_uint32 resultHi;
2449
2450 DRFLAC_ASSERT(bitCountHi > 0);
2451 DRFLAC_ASSERT(bitCountHi < 32);
2452 resultHi = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountHi);
2453
2454 if (!drflac__reload_cache(bs)) {
2455 return DRFLAC_FALSE;
2456 }
2457 if (bitCountLo > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
2458 /* This happens when we get to end of stream */
2459 return DRFLAC_FALSE;
2460 }
2461
2462 *pResultOut = (resultHi << bitCountLo) | (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountLo);
2463 bs->consumedBits += bitCountLo;
2464 bs->cache <<= bitCountLo;
2465 return DRFLAC_TRUE;
2466 }
2467}
2468
2469static drflac_bool32 drflac__read_int32(drflac_bs* bs, unsigned int bitCount, drflac_int32* pResult)
2470{
2471 drflac_uint32 result;
2472
2473 DRFLAC_ASSERT(bs != NULL);
2474 DRFLAC_ASSERT(pResult != NULL);
2475 DRFLAC_ASSERT(bitCount > 0);
2476 DRFLAC_ASSERT(bitCount <= 32);
2477
2478 if (!drflac__read_uint32(bs, bitCount, &result)) {
2479 return DRFLAC_FALSE;
2480 }
2481
2482 /* Do not attempt to shift by 32 as it's undefined. */
2483 if (bitCount < 32) {
2484 drflac_uint32 signbit;
2485 signbit = ((result >> (bitCount-1)) & 0x01);
2486 result |= (~signbit + 1) << bitCount;
2487 }
2488
2489 *pResult = (drflac_int32)result;
2490 return DRFLAC_TRUE;
2491}
2492
2493#ifdef DRFLAC_64BIT
2494static drflac_bool32 drflac__read_uint64(drflac_bs* bs, unsigned int bitCount, drflac_uint64* pResultOut)
2495{
2496 drflac_uint32 resultHi;
2497 drflac_uint32 resultLo;
2498
2499 DRFLAC_ASSERT(bitCount <= 64);
2500 DRFLAC_ASSERT(bitCount > 32);
2501
2502 if (!drflac__read_uint32(bs, bitCount - 32, &resultHi)) {
2503 return DRFLAC_FALSE;
2504 }
2505
2506 if (!drflac__read_uint32(bs, 32, &resultLo)) {
2507 return DRFLAC_FALSE;
2508 }
2509
2510 *pResultOut = (((drflac_uint64)resultHi) << 32) | ((drflac_uint64)resultLo);
2511 return DRFLAC_TRUE;
2512}
2513#endif
2514
2515/* Function below is unused, but leaving it here in case I need to quickly add it again. */
2516#if 0
2517static drflac_bool32 drflac__read_int64(drflac_bs* bs, unsigned int bitCount, drflac_int64* pResultOut)
2518{
2519 drflac_uint64 result;
2520 drflac_uint64 signbit;
2521
2522 DRFLAC_ASSERT(bitCount <= 64);
2523
2524 if (!drflac__read_uint64(bs, bitCount, &result)) {
2525 return DRFLAC_FALSE;
2526 }
2527
2528 signbit = ((result >> (bitCount-1)) & 0x01);
2529 result |= (~signbit + 1) << bitCount;
2530
2531 *pResultOut = (drflac_int64)result;
2532 return DRFLAC_TRUE;
2533}
2534#endif
2535
2536static drflac_bool32 drflac__read_uint16(drflac_bs* bs, unsigned int bitCount, drflac_uint16* pResult)
2537{
2538 drflac_uint32 result;
2539
2540 DRFLAC_ASSERT(bs != NULL);
2541 DRFLAC_ASSERT(pResult != NULL);
2542 DRFLAC_ASSERT(bitCount > 0);
2543 DRFLAC_ASSERT(bitCount <= 16);
2544
2545 if (!drflac__read_uint32(bs, bitCount, &result)) {
2546 return DRFLAC_FALSE;
2547 }
2548
2549 *pResult = (drflac_uint16)result;
2550 return DRFLAC_TRUE;
2551}
2552
2553#if 0
2554static drflac_bool32 drflac__read_int16(drflac_bs* bs, unsigned int bitCount, drflac_int16* pResult)
2555{
2556 drflac_int32 result;
2557
2558 DRFLAC_ASSERT(bs != NULL);
2559 DRFLAC_ASSERT(pResult != NULL);
2560 DRFLAC_ASSERT(bitCount > 0);
2561 DRFLAC_ASSERT(bitCount <= 16);
2562
2563 if (!drflac__read_int32(bs, bitCount, &result)) {
2564 return DRFLAC_FALSE;
2565 }
2566
2567 *pResult = (drflac_int16)result;
2568 return DRFLAC_TRUE;
2569}
2570#endif
2571
2572static drflac_bool32 drflac__read_uint8(drflac_bs* bs, unsigned int bitCount, drflac_uint8* pResult)
2573{
2574 drflac_uint32 result;
2575
2576 DRFLAC_ASSERT(bs != NULL);
2577 DRFLAC_ASSERT(pResult != NULL);
2578 DRFLAC_ASSERT(bitCount > 0);
2579 DRFLAC_ASSERT(bitCount <= 8);
2580
2581 if (!drflac__read_uint32(bs, bitCount, &result)) {
2582 return DRFLAC_FALSE;
2583 }
2584
2585 *pResult = (drflac_uint8)result;
2586 return DRFLAC_TRUE;
2587}
2588
2589static drflac_bool32 drflac__read_int8(drflac_bs* bs, unsigned int bitCount, drflac_int8* pResult)
2590{
2591 drflac_int32 result;
2592
2593 DRFLAC_ASSERT(bs != NULL);
2594 DRFLAC_ASSERT(pResult != NULL);
2595 DRFLAC_ASSERT(bitCount > 0);
2596 DRFLAC_ASSERT(bitCount <= 8);
2597
2598 if (!drflac__read_int32(bs, bitCount, &result)) {
2599 return DRFLAC_FALSE;
2600 }
2601
2602 *pResult = (drflac_int8)result;
2603 return DRFLAC_TRUE;
2604}
2605
2606
2607static drflac_bool32 drflac__seek_bits(drflac_bs* bs, size_t bitsToSeek)
2608{
2609 if (bitsToSeek <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
2610 bs->consumedBits += (drflac_uint32)bitsToSeek;
2611 bs->cache <<= bitsToSeek;
2612 return DRFLAC_TRUE;
2613 } else {
2614 /* It straddles the cached data. This function isn't called too frequently so I'm favouring simplicity here. */
2615 bitsToSeek -= DRFLAC_CACHE_L1_BITS_REMAINING(bs);
2616 bs->consumedBits += DRFLAC_CACHE_L1_BITS_REMAINING(bs);
2617 bs->cache = 0;
2618
2619 /* Simple case. Seek in groups of the same number as bits that fit within a cache line. */
2620#ifdef DRFLAC_64BIT
2621 while (bitsToSeek >= DRFLAC_CACHE_L1_SIZE_BITS(bs)) {
2622 drflac_uint64 bin;
2623 if (!drflac__read_uint64(bs, DRFLAC_CACHE_L1_SIZE_BITS(bs), &bin)) {
2624 return DRFLAC_FALSE;
2625 }
2626 bitsToSeek -= DRFLAC_CACHE_L1_SIZE_BITS(bs);
2627 }
2628#else
2629 while (bitsToSeek >= DRFLAC_CACHE_L1_SIZE_BITS(bs)) {
2630 drflac_uint32 bin;
2631 if (!drflac__read_uint32(bs, DRFLAC_CACHE_L1_SIZE_BITS(bs), &bin)) {
2632 return DRFLAC_FALSE;
2633 }
2634 bitsToSeek -= DRFLAC_CACHE_L1_SIZE_BITS(bs);
2635 }
2636#endif
2637
2638 /* Whole leftover bytes. */
2639 while (bitsToSeek >= 8) {
2640 drflac_uint8 bin;
2641 if (!drflac__read_uint8(bs, 8, &bin)) {
2642 return DRFLAC_FALSE;
2643 }
2644 bitsToSeek -= 8;
2645 }
2646
2647 /* Leftover bits. */
2648 if (bitsToSeek > 0) {
2649 drflac_uint8 bin;
2650 if (!drflac__read_uint8(bs, (drflac_uint32)bitsToSeek, &bin)) {
2651 return DRFLAC_FALSE;
2652 }
2653 bitsToSeek = 0; /* <-- Necessary for the assert below. */
2654 }
2655
2656 DRFLAC_ASSERT(bitsToSeek == 0);
2657 return DRFLAC_TRUE;
2658 }
2659}
2660
2661
2662/* This function moves the bit streamer to the first bit after the sync code (bit 15 of the of the frame header). It will also update the CRC-16. */
2663static drflac_bool32 drflac__find_and_seek_to_next_sync_code(drflac_bs* bs)
2664{
2665 DRFLAC_ASSERT(bs != NULL);
2666
2667 /*
2668 The sync code is always aligned to 8 bits. This is convenient for us because it means we can do byte-aligned movements. The first
2669 thing to do is align to the next byte.
2670 */
2671 if (!drflac__seek_bits(bs, DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7)) {
2672 return DRFLAC_FALSE;
2673 }
2674
2675 for (;;) {
2676 drflac_uint8 hi;
2677
2678#ifndef DR_FLAC_NO_CRC
2679 drflac__reset_crc16(bs);
2680#endif
2681
2682 if (!drflac__read_uint8(bs, 8, &hi)) {
2683 return DRFLAC_FALSE;
2684 }
2685
2686 if (hi == 0xFF) {
2687 drflac_uint8 lo;
2688 if (!drflac__read_uint8(bs, 6, &lo)) {
2689 return DRFLAC_FALSE;
2690 }
2691
2692 if (lo == 0x3E) {
2693 return DRFLAC_TRUE;
2694 } else {
2695 if (!drflac__seek_bits(bs, DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7)) {
2696 return DRFLAC_FALSE;
2697 }
2698 }
2699 }
2700 }
2701
2702 /* Should never get here. */
2703 /*return DRFLAC_FALSE;*/
2704}
2705
2706
2707#if defined(DRFLAC_HAS_LZCNT_INTRINSIC)
2708#define DRFLAC_IMPLEMENT_CLZ_LZCNT
2709#endif
2710#if defined(_MSC_VER) && _MSC_VER >= 1400 && (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(__clang__)
2711#define DRFLAC_IMPLEMENT_CLZ_MSVC
2712#endif
2713#if defined(__WATCOMC__) && defined(__386__)
2714#define DRFLAC_IMPLEMENT_CLZ_WATCOM
2715#endif
2716#ifdef __MRC__
2717#include <intrinsics.h>
2718#define DRFLAC_IMPLEMENT_CLZ_MRC
2719#endif
2720
2721static DRFLAC_INLINE drflac_uint32 drflac__clz_software(drflac_cache_t x)
2722{
2723 drflac_uint32 n;
2724 static drflac_uint32 clz_table_4[] = {
2725 0,
2726 4,
2727 3, 3,
2728 2, 2, 2, 2,
2729 1, 1, 1, 1, 1, 1, 1, 1
2730 };
2731
2732 if (x == 0) {
2733 return sizeof(x)*8;
2734 }
2735
2736 n = clz_table_4[x >> (sizeof(x)*8 - 4)];
2737 if (n == 0) {
2738#ifdef DRFLAC_64BIT
2739 if ((x & ((drflac_uint64)0xFFFFFFFF << 32)) == 0) { n = 32; x <<= 32; }
2740 if ((x & ((drflac_uint64)0xFFFF0000 << 32)) == 0) { n += 16; x <<= 16; }
2741 if ((x & ((drflac_uint64)0xFF000000 << 32)) == 0) { n += 8; x <<= 8; }
2742 if ((x & ((drflac_uint64)0xF0000000 << 32)) == 0) { n += 4; x <<= 4; }
2743#else
2744 if ((x & 0xFFFF0000) == 0) { n = 16; x <<= 16; }
2745 if ((x & 0xFF000000) == 0) { n += 8; x <<= 8; }
2746 if ((x & 0xF0000000) == 0) { n += 4; x <<= 4; }
2747#endif
2748 n += clz_table_4[x >> (sizeof(x)*8 - 4)];
2749 }
2750
2751 return n - 1;
2752}
2753
2754#ifdef DRFLAC_IMPLEMENT_CLZ_LZCNT
2755static DRFLAC_INLINE drflac_bool32 drflac__is_lzcnt_supported(void)
2756{
2757 /* Fast compile time check for ARM. */
2758#if defined(DRFLAC_HAS_LZCNT_INTRINSIC) && defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5)
2759 return DRFLAC_TRUE;
2760#elif defined(__MRC__)
2761 return DRFLAC_TRUE;
2762#else
2763 /* If the compiler itself does not support the intrinsic then we'll need to return false. */
2764 #ifdef DRFLAC_HAS_LZCNT_INTRINSIC
2765 return drflac__gIsLZCNTSupported;
2766 #else
2767 return DRFLAC_FALSE;
2768 #endif
2769#endif
2770}
2771
2772static DRFLAC_INLINE drflac_uint32 drflac__clz_lzcnt(drflac_cache_t x)
2773{
2774 /*
2775 It's critical for competitive decoding performance that this function be highly optimal. With MSVC we can use the __lzcnt64() and __lzcnt() intrinsics
2776 to achieve good performance, however on GCC and Clang it's a little bit more annoying. The __builtin_clzl() and __builtin_clzll() intrinsics leave
2777 it undefined as to the return value when `x` is 0. We need this to be well defined as returning 32 or 64, depending on whether or not it's a 32- or
2778 64-bit build. To work around this we would need to add a conditional to check for the x = 0 case, but this creates unnecessary inefficiency. To work
2779 around this problem I have written some inline assembly to emit the LZCNT (x86) or CLZ (ARM) instruction directly which removes the need to include
2780 the conditional. This has worked well in the past, but for some reason Clang's MSVC compatible driver, clang-cl, does not seem to be handling this
2781 in the same way as the normal Clang driver. It seems that `clang-cl` is just outputting the wrong results sometimes, maybe due to some register
2782 getting clobbered?
2783
2784 I'm not sure if this is a bug with dr_flac's inlined assembly (most likely), a bug in `clang-cl` or just a misunderstanding on my part with inline
2785 assembly rules for `clang-cl`. If somebody can identify an error in dr_flac's inlined assembly I'm happy to get that fixed.
2786
2787 Fortunately there is an easy workaround for this. Clang implements MSVC-specific intrinsics for compatibility. It also defines _MSC_VER for extra
2788 compatibility. We can therefore just check for _MSC_VER and use the MSVC intrinsic which, fortunately for us, Clang supports. It would still be nice
2789 to know how to fix the inlined assembly for correctness sake, however.
2790 */
2791
2792#if defined(_MSC_VER) /*&& !defined(__clang__)*/ /* <-- Intentionally wanting Clang to use the MSVC __lzcnt64/__lzcnt intrinsics due to above ^. */
2793 #ifdef DRFLAC_64BIT
2794 return (drflac_uint32)__lzcnt64(x);
2795 #else
2796 return (drflac_uint32)__lzcnt(x);
2797 #endif
2798#else
2799 #if defined(__GNUC__) || defined(__clang__)
2800 #if defined(DRFLAC_X64)
2801 {
2802 drflac_uint64 r;
2803 __asm__ __volatile__ (
2804 "lzcnt{ %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"
2805 );
2806
2807 return (drflac_uint32)r;
2808 }
2809 #elif defined(DRFLAC_X86)
2810 {
2811 drflac_uint32 r;
2812 __asm__ __volatile__ (
2813 "lzcnt{l %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"
2814 );
2815
2816 return r;
2817 }
2818 #elif defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) && !defined(__ARM_ARCH_6M__) && !defined(DRFLAC_64BIT) /* <-- I haven't tested 64-bit inline assembly, so only enabling this for the 32-bit build for now. */
2819 {
2820 unsigned int r;
2821 __asm__ __volatile__ (
2822 #if defined(DRFLAC_64BIT)
2823 "clz %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(x) /* <-- This is untested. If someone in the community could test this, that would be appreciated! */
2824 #else
2825 "clz %[out], %[in]" : [out]"=r"(r) : [in]"r"(x)
2826 #endif
2827 );
2828
2829 return r;
2830 }
2831 #else
2832 if (x == 0) {
2833 return sizeof(x)*8;
2834 }
2835 #ifdef DRFLAC_64BIT
2836 return (drflac_uint32)__builtin_clzll((drflac_uint64)x);
2837 #else
2838 return (drflac_uint32)__builtin_clzl((drflac_uint32)x);
2839 #endif
2840 #endif
2841 #else
2842 /* Unsupported compiler. */
2843 #error "This compiler does not support the lzcnt intrinsic."
2844 #endif
2845#endif
2846}
2847#endif
2848
2849#ifdef DRFLAC_IMPLEMENT_CLZ_MSVC
2850#include <intrin.h> /* For BitScanReverse(). */
2851
2852static DRFLAC_INLINE drflac_uint32 drflac__clz_msvc(drflac_cache_t x)
2853{
2854 drflac_uint32 n;
2855
2856 if (x == 0) {
2857 return sizeof(x)*8;
2858 }
2859
2860#ifdef DRFLAC_64BIT
2861 _BitScanReverse64((unsigned long*)&n, x);
2862#else
2863 _BitScanReverse((unsigned long*)&n, x);
2864#endif
2865 return sizeof(x)*8 - n - 1;
2866}
2867#endif
2868
2869#ifdef DRFLAC_IMPLEMENT_CLZ_WATCOM
2870static __inline drflac_uint32 drflac__clz_watcom (drflac_uint32);
2871#ifdef DRFLAC_IMPLEMENT_CLZ_WATCOM_LZCNT
2872/* Use the LZCNT instruction (only available on some processors since the 2010s). */
2873#pragma aux drflac__clz_watcom_lzcnt = \
2874 "db 0F3h, 0Fh, 0BDh, 0C0h" /* lzcnt eax, eax */ \
2875 parm [eax] \
2876 value [eax] \
2877 modify nomemory;
2878#else
2879/* Use the 386+-compatible implementation. */
2880#pragma aux drflac__clz_watcom = \
2881 "bsr eax, eax" \
2882 "xor eax, 31" \
2883 parm [eax] nomemory \
2884 value [eax] \
2885 modify exact [eax] nomemory;
2886#endif
2887#endif
2888
2889static DRFLAC_INLINE drflac_uint32 drflac__clz(drflac_cache_t x)
2890{
2891#ifdef DRFLAC_IMPLEMENT_CLZ_LZCNT
2892 if (drflac__is_lzcnt_supported()) {
2893 return drflac__clz_lzcnt(x);
2894 } else
2895#endif
2896 {
2897#ifdef DRFLAC_IMPLEMENT_CLZ_MSVC
2898 return drflac__clz_msvc(x);
2899#elif defined(DRFLAC_IMPLEMENT_CLZ_WATCOM_LZCNT)
2900 return drflac__clz_watcom_lzcnt(x);
2901#elif defined(DRFLAC_IMPLEMENT_CLZ_WATCOM)
2902 return (x == 0) ? sizeof(x)*8 : drflac__clz_watcom(x);
2903#elif defined(__MRC__)
2904 return __cntlzw(x);
2905#else
2906 return drflac__clz_software(x);
2907#endif
2908 }
2909}
2910
2911
2912static DRFLAC_INLINE drflac_bool32 drflac__seek_past_next_set_bit(drflac_bs* bs, unsigned int* pOffsetOut)
2913{
2914 drflac_uint32 zeroCounter = 0;
2915 drflac_uint32 setBitOffsetPlus1;
2916
2917 while (bs->cache == 0) {
2918 zeroCounter += (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs);
2919 if (!drflac__reload_cache(bs)) {
2920 return DRFLAC_FALSE;
2921 }
2922 }
2923
2924 if (bs->cache == 1) {
2925 /* Not catching this would lead to undefined behaviour: a shift of a 32-bit number by 32 or more is undefined */
2926 *pOffsetOut = zeroCounter + (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs) - 1;
2927 if (!drflac__reload_cache(bs)) {
2928 return DRFLAC_FALSE;
2929 }
2930
2931 return DRFLAC_TRUE;
2932 }
2933
2934 setBitOffsetPlus1 = drflac__clz(bs->cache);
2935 setBitOffsetPlus1 += 1;
2936
2937 if (setBitOffsetPlus1 > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
2938 /* This happens when we get to end of stream */
2939 return DRFLAC_FALSE;
2940 }
2941
2942 bs->consumedBits += setBitOffsetPlus1;
2943 bs->cache <<= setBitOffsetPlus1;
2944
2945 *pOffsetOut = zeroCounter + setBitOffsetPlus1 - 1;
2946 return DRFLAC_TRUE;
2947}
2948
2949
2950
2951static drflac_bool32 drflac__seek_to_byte(drflac_bs* bs, drflac_uint64 offsetFromStart)
2952{
2953 DRFLAC_ASSERT(bs != NULL);
2954 DRFLAC_ASSERT(offsetFromStart > 0);
2955
2956 /*
2957 Seeking from the start is not quite as trivial as it sounds because the onSeek callback takes a signed 32-bit integer (which
2958 is intentional because it simplifies the implementation of the onSeek callbacks), however offsetFromStart is unsigned 64-bit.
2959 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.
2960 */
2961 if (offsetFromStart > 0x7FFFFFFF) {
2962 drflac_uint64 bytesRemaining = offsetFromStart;
2963 if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) {
2964 return DRFLAC_FALSE;
2965 }
2966 bytesRemaining -= 0x7FFFFFFF;
2967
2968 while (bytesRemaining > 0x7FFFFFFF) {
2969 if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_current)) {
2970 return DRFLAC_FALSE;
2971 }
2972 bytesRemaining -= 0x7FFFFFFF;
2973 }
2974
2975 if (bytesRemaining > 0) {
2976 if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, drflac_seek_origin_current)) {
2977 return DRFLAC_FALSE;
2978 }
2979 }
2980 } else {
2981 if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, drflac_seek_origin_start)) {
2982 return DRFLAC_FALSE;
2983 }
2984 }
2985
2986 /* The cache should be reset to force a reload of fresh data from the client. */
2987 drflac__reset_cache(bs);
2988 return DRFLAC_TRUE;
2989}
2990
2991
2992static drflac_result drflac__read_utf8_coded_number(drflac_bs* bs, drflac_uint64* pNumberOut, drflac_uint8* pCRCOut)
2993{
2994 drflac_uint8 crc;
2995 drflac_uint64 result;
2996 drflac_uint8 utf8[7] = {0};
2997 int byteCount;
2998 int i;
2999
3000 DRFLAC_ASSERT(bs != NULL);
3001 DRFLAC_ASSERT(pNumberOut != NULL);
3002 DRFLAC_ASSERT(pCRCOut != NULL);
3003
3004 crc = *pCRCOut;
3005
3006 if (!drflac__read_uint8(bs, 8, utf8)) {
3007 *pNumberOut = 0;
3008 return DRFLAC_AT_END;
3009 }
3010 crc = drflac_crc8(crc, utf8[0], 8);
3011
3012 if ((utf8[0] & 0x80) == 0) {
3013 *pNumberOut = utf8[0];
3014 *pCRCOut = crc;
3015 return DRFLAC_SUCCESS;
3016 }
3017
3018 /*byteCount = 1;*/
3019 if ((utf8[0] & 0xE0) == 0xC0) {
3020 byteCount = 2;
3021 } else if ((utf8[0] & 0xF0) == 0xE0) {
3022 byteCount = 3;
3023 } else if ((utf8[0] & 0xF8) == 0xF0) {
3024 byteCount = 4;
3025 } else if ((utf8[0] & 0xFC) == 0xF8) {
3026 byteCount = 5;
3027 } else if ((utf8[0] & 0xFE) == 0xFC) {
3028 byteCount = 6;
3029 } else if ((utf8[0] & 0xFF) == 0xFE) {
3030 byteCount = 7;
3031 } else {
3032 *pNumberOut = 0;
3033 return DRFLAC_CRC_MISMATCH; /* Bad UTF-8 encoding. */
3034 }
3035
3036 /* Read extra bytes. */
3037 DRFLAC_ASSERT(byteCount > 1);
3038
3039 result = (drflac_uint64)(utf8[0] & (0xFF >> (byteCount + 1)));
3040 for (i = 1; i < byteCount; ++i) {
3041 if (!drflac__read_uint8(bs, 8, utf8 + i)) {
3042 *pNumberOut = 0;
3043 return DRFLAC_AT_END;
3044 }
3045 crc = drflac_crc8(crc, utf8[i], 8);
3046
3047 result = (result << 6) | (utf8[i] & 0x3F);
3048 }
3049
3050 *pNumberOut = result;
3051 *pCRCOut = crc;
3052 return DRFLAC_SUCCESS;
3053}
3054
3055
3056static DRFLAC_INLINE drflac_uint32 drflac__ilog2_u32(drflac_uint32 x)
3057{
3058#if 1 /* Needs optimizing. */
3059 drflac_uint32 result = 0;
3060 while (x > 0) {
3061 result += 1;
3062 x >>= 1;
3063 }
3064
3065 return result;
3066#endif
3067}
3068
3069static DRFLAC_INLINE drflac_bool32 drflac__use_64_bit_prediction(drflac_uint32 bitsPerSample, drflac_uint32 order, drflac_uint32 precision)
3070{
3071 /* https://web.archive.org/web/20220205005724/https://github.com/ietf-wg-cellar/flac-specification/blob/37a49aa48ba4ba12e8757badfc59c0df35435fec/rfc_backmatter.md */
3072 return bitsPerSample + precision + drflac__ilog2_u32(order) > 32;
3073}
3074
3075
3076/*
3077The next two functions are responsible for calculating the prediction.
3078
3079When the bits per sample is >16 we need to use 64-bit integer arithmetic because otherwise we'll run out of precision. It's
3080safe to assume this will be slower on 32-bit platforms so we use a more optimal solution when the bits per sample is <=16.
3081*/
3082#if defined(__clang__)
3083__attribute__((no_sanitize("signed-integer-overflow")))
3084#endif
3085static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_32(drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples)
3086{
3087 drflac_int32 prediction = 0;
3088
3089 DRFLAC_ASSERT(order <= 32);
3090
3091 /* 32-bit version. */
3092
3093 /* VC++ optimizes this to a single jmp. I've not yet verified this for other compilers. */
3094 switch (order)
3095 {
3096 case 32: prediction += coefficients[31] * pDecodedSamples[-32];
3097 case 31: prediction += coefficients[30] * pDecodedSamples[-31];
3098 case 30: prediction += coefficients[29] * pDecodedSamples[-30];
3099 case 29: prediction += coefficients[28] * pDecodedSamples[-29];
3100 case 28: prediction += coefficients[27] * pDecodedSamples[-28];
3101 case 27: prediction += coefficients[26] * pDecodedSamples[-27];
3102 case 26: prediction += coefficients[25] * pDecodedSamples[-26];
3103 case 25: prediction += coefficients[24] * pDecodedSamples[-25];
3104 case 24: prediction += coefficients[23] * pDecodedSamples[-24];
3105 case 23: prediction += coefficients[22] * pDecodedSamples[-23];
3106 case 22: prediction += coefficients[21] * pDecodedSamples[-22];
3107 case 21: prediction += coefficients[20] * pDecodedSamples[-21];
3108 case 20: prediction += coefficients[19] * pDecodedSamples[-20];
3109 case 19: prediction += coefficients[18] * pDecodedSamples[-19];
3110 case 18: prediction += coefficients[17] * pDecodedSamples[-18];
3111 case 17: prediction += coefficients[16] * pDecodedSamples[-17];
3112 case 16: prediction += coefficients[15] * pDecodedSamples[-16];
3113 case 15: prediction += coefficients[14] * pDecodedSamples[-15];
3114 case 14: prediction += coefficients[13] * pDecodedSamples[-14];
3115 case 13: prediction += coefficients[12] * pDecodedSamples[-13];
3116 case 12: prediction += coefficients[11] * pDecodedSamples[-12];
3117 case 11: prediction += coefficients[10] * pDecodedSamples[-11];
3118 case 10: prediction += coefficients[ 9] * pDecodedSamples[-10];
3119 case 9: prediction += coefficients[ 8] * pDecodedSamples[- 9];
3120 case 8: prediction += coefficients[ 7] * pDecodedSamples[- 8];
3121 case 7: prediction += coefficients[ 6] * pDecodedSamples[- 7];
3122 case 6: prediction += coefficients[ 5] * pDecodedSamples[- 6];
3123 case 5: prediction += coefficients[ 4] * pDecodedSamples[- 5];
3124 case 4: prediction += coefficients[ 3] * pDecodedSamples[- 4];
3125 case 3: prediction += coefficients[ 2] * pDecodedSamples[- 3];
3126 case 2: prediction += coefficients[ 1] * pDecodedSamples[- 2];
3127 case 1: prediction += coefficients[ 0] * pDecodedSamples[- 1];
3128 }
3129
3130 return (drflac_int32)(prediction >> shift);
3131}
3132
3133static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_64(drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples)
3134{
3135 drflac_int64 prediction;
3136
3137 DRFLAC_ASSERT(order <= 32);
3138
3139 /* 64-bit version. */
3140
3141 /* This method is faster on the 32-bit build when compiling with VC++. See note below. */
3142#ifndef DRFLAC_64BIT
3143 if (order == 8)
3144 {
3145 prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
3146 prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
3147 prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
3148 prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4];
3149 prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5];
3150 prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6];
3151 prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7];
3152 prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8];
3153 }
3154 else if (order == 7)
3155 {
3156 prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
3157 prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
3158 prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
3159 prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4];
3160 prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5];
3161 prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6];
3162 prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7];
3163 }
3164 else if (order == 3)
3165 {
3166 prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
3167 prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
3168 prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
3169 }
3170 else if (order == 6)
3171 {
3172 prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
3173 prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
3174 prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
3175 prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4];
3176 prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5];
3177 prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6];
3178 }
3179 else if (order == 5)
3180 {
3181 prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
3182 prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
3183 prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
3184 prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4];
3185 prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5];
3186 }
3187 else if (order == 4)
3188 {
3189 prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
3190 prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
3191 prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
3192 prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4];
3193 }
3194 else if (order == 12)
3195 {
3196 prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
3197 prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
3198 prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
3199 prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4];
3200 prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5];
3201 prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6];
3202 prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7];
3203 prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8];
3204 prediction += coefficients[8] * (drflac_int64)pDecodedSamples[-9];
3205 prediction += coefficients[9] * (drflac_int64)pDecodedSamples[-10];
3206 prediction += coefficients[10] * (drflac_int64)pDecodedSamples[-11];
3207 prediction += coefficients[11] * (drflac_int64)pDecodedSamples[-12];
3208 }
3209 else if (order == 2)
3210 {
3211 prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
3212 prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
3213 }
3214 else if (order == 1)
3215 {
3216 prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
3217 }
3218 else if (order == 10)
3219 {
3220 prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
3221 prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
3222 prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
3223 prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4];
3224 prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5];
3225 prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6];
3226 prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7];
3227 prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8];
3228 prediction += coefficients[8] * (drflac_int64)pDecodedSamples[-9];
3229 prediction += coefficients[9] * (drflac_int64)pDecodedSamples[-10];
3230 }
3231 else if (order == 9)
3232 {
3233 prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
3234 prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
3235 prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
3236 prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4];
3237 prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5];
3238 prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6];
3239 prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7];
3240 prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8];
3241 prediction += coefficients[8] * (drflac_int64)pDecodedSamples[-9];
3242 }
3243 else if (order == 11)
3244 {
3245 prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
3246 prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
3247 prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
3248 prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4];
3249 prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5];
3250 prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6];
3251 prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7];
3252 prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8];
3253 prediction += coefficients[8] * (drflac_int64)pDecodedSamples[-9];
3254 prediction += coefficients[9] * (drflac_int64)pDecodedSamples[-10];
3255 prediction += coefficients[10] * (drflac_int64)pDecodedSamples[-11];
3256 }
3257 else
3258 {
3259 int j;
3260
3261 prediction = 0;
3262 for (j = 0; j < (int)order; ++j) {
3263 prediction += coefficients[j] * (drflac_int64)pDecodedSamples[-j-1];
3264 }
3265 }
3266#endif
3267
3268 /*
3269 VC++ optimizes this to a single jmp instruction, but only the 64-bit build. The 32-bit build generates less efficient code for some
3270 reason. The ugly version above is faster so we'll just switch between the two depending on the target platform.
3271 */
3272#ifdef DRFLAC_64BIT
3273 prediction = 0;
3274 switch (order)
3275 {
3276 case 32: prediction += coefficients[31] * (drflac_int64)pDecodedSamples[-32];
3277 case 31: prediction += coefficients[30] * (drflac_int64)pDecodedSamples[-31];
3278 case 30: prediction += coefficients[29] * (drflac_int64)pDecodedSamples[-30];
3279 case 29: prediction += coefficients[28] * (drflac_int64)pDecodedSamples[-29];
3280 case 28: prediction += coefficients[27] * (drflac_int64)pDecodedSamples[-28];
3281 case 27: prediction += coefficients[26] * (drflac_int64)pDecodedSamples[-27];
3282 case 26: prediction += coefficients[25] * (drflac_int64)pDecodedSamples[-26];
3283 case 25: prediction += coefficients[24] * (drflac_int64)pDecodedSamples[-25];
3284 case 24: prediction += coefficients[23] * (drflac_int64)pDecodedSamples[-24];
3285 case 23: prediction += coefficients[22] * (drflac_int64)pDecodedSamples[-23];
3286 case 22: prediction += coefficients[21] * (drflac_int64)pDecodedSamples[-22];
3287 case 21: prediction += coefficients[20] * (drflac_int64)pDecodedSamples[-21];
3288 case 20: prediction += coefficients[19] * (drflac_int64)pDecodedSamples[-20];
3289 case 19: prediction += coefficients[18] * (drflac_int64)pDecodedSamples[-19];
3290 case 18: prediction += coefficients[17] * (drflac_int64)pDecodedSamples[-18];
3291 case 17: prediction += coefficients[16] * (drflac_int64)pDecodedSamples[-17];
3292 case 16: prediction += coefficients[15] * (drflac_int64)pDecodedSamples[-16];
3293 case 15: prediction += coefficients[14] * (drflac_int64)pDecodedSamples[-15];
3294 case 14: prediction += coefficients[13] * (drflac_int64)pDecodedSamples[-14];
3295 case 13: prediction += coefficients[12] * (drflac_int64)pDecodedSamples[-13];
3296 case 12: prediction += coefficients[11] * (drflac_int64)pDecodedSamples[-12];
3297 case 11: prediction += coefficients[10] * (drflac_int64)pDecodedSamples[-11];
3298 case 10: prediction += coefficients[ 9] * (drflac_int64)pDecodedSamples[-10];
3299 case 9: prediction += coefficients[ 8] * (drflac_int64)pDecodedSamples[- 9];
3300 case 8: prediction += coefficients[ 7] * (drflac_int64)pDecodedSamples[- 8];
3301 case 7: prediction += coefficients[ 6] * (drflac_int64)pDecodedSamples[- 7];
3302 case 6: prediction += coefficients[ 5] * (drflac_int64)pDecodedSamples[- 6];
3303 case 5: prediction += coefficients[ 4] * (drflac_int64)pDecodedSamples[- 5];
3304 case 4: prediction += coefficients[ 3] * (drflac_int64)pDecodedSamples[- 4];
3305 case 3: prediction += coefficients[ 2] * (drflac_int64)pDecodedSamples[- 3];
3306 case 2: prediction += coefficients[ 1] * (drflac_int64)pDecodedSamples[- 2];
3307 case 1: prediction += coefficients[ 0] * (drflac_int64)pDecodedSamples[- 1];
3308 }
3309#endif
3310
3311 return (drflac_int32)(prediction >> shift);
3312}
3313
3314
3315#if 0
3316/*
3317Reference implementation for reading and decoding samples with residual. This is intentionally left unoptimized for the
3318sake of readability and should only be used as a reference.
3319*/
3320static drflac_bool32 drflac__decode_samples_with_residual__rice__reference(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
3321{
3322 drflac_uint32 i;
3323
3324 DRFLAC_ASSERT(bs != NULL);
3325 DRFLAC_ASSERT(pSamplesOut != NULL);
3326
3327 for (i = 0; i < count; ++i) {
3328 drflac_uint32 zeroCounter = 0;
3329 for (;;) {
3330 drflac_uint8 bit;
3331 if (!drflac__read_uint8(bs, 1, &bit)) {
3332 return DRFLAC_FALSE;
3333 }
3334
3335 if (bit == 0) {
3336 zeroCounter += 1;
3337 } else {
3338 break;
3339 }
3340 }
3341
3342 drflac_uint32 decodedRice;
3343 if (riceParam > 0) {
3344 if (!drflac__read_uint32(bs, riceParam, &decodedRice)) {
3345 return DRFLAC_FALSE;
3346 }
3347 } else {
3348 decodedRice = 0;
3349 }
3350
3351 decodedRice |= (zeroCounter << riceParam);
3352 if ((decodedRice & 0x01)) {
3353 decodedRice = ~(decodedRice >> 1);
3354 } else {
3355 decodedRice = (decodedRice >> 1);
3356 }
3357
3358
3359 if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) {
3360 pSamplesOut[i] = decodedRice + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + i);
3361 } else {
3362 pSamplesOut[i] = decodedRice + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + i);
3363 }
3364 }
3365
3366 return DRFLAC_TRUE;
3367}
3368#endif
3369
3370#if 0
3371static drflac_bool32 drflac__read_rice_parts__reference(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut)
3372{
3373 drflac_uint32 zeroCounter = 0;
3374 drflac_uint32 decodedRice;
3375
3376 for (;;) {
3377 drflac_uint8 bit;
3378 if (!drflac__read_uint8(bs, 1, &bit)) {
3379 return DRFLAC_FALSE;
3380 }
3381
3382 if (bit == 0) {
3383 zeroCounter += 1;
3384 } else {
3385 break;
3386 }
3387 }
3388
3389 if (riceParam > 0) {
3390 if (!drflac__read_uint32(bs, riceParam, &decodedRice)) {
3391 return DRFLAC_FALSE;
3392 }
3393 } else {
3394 decodedRice = 0;
3395 }
3396
3397 *pZeroCounterOut = zeroCounter;
3398 *pRiceParamPartOut = decodedRice;
3399 return DRFLAC_TRUE;
3400}
3401#endif
3402
3403#if 0
3404static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut)
3405{
3406 drflac_cache_t riceParamMask;
3407 drflac_uint32 zeroCounter;
3408 drflac_uint32 setBitOffsetPlus1;
3409 drflac_uint32 riceParamPart;
3410 drflac_uint32 riceLength;
3411
3412 DRFLAC_ASSERT(riceParam > 0); /* <-- riceParam should never be 0. drflac__read_rice_parts__param_equals_zero() should be used instead for this case. */
3413
3414 riceParamMask = DRFLAC_CACHE_L1_SELECTION_MASK(riceParam);
3415
3416 zeroCounter = 0;
3417 while (bs->cache == 0) {
3418 zeroCounter += (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs);
3419 if (!drflac__reload_cache(bs)) {
3420 return DRFLAC_FALSE;
3421 }
3422 }
3423
3424 setBitOffsetPlus1 = drflac__clz(bs->cache);
3425 zeroCounter += setBitOffsetPlus1;
3426 setBitOffsetPlus1 += 1;
3427
3428 riceLength = setBitOffsetPlus1 + riceParam;
3429 if (riceLength < DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
3430 riceParamPart = (drflac_uint32)((bs->cache & (riceParamMask >> setBitOffsetPlus1)) >> DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceLength));
3431
3432 bs->consumedBits += riceLength;
3433 bs->cache <<= riceLength;
3434 } else {
3435 drflac_uint32 bitCountLo;
3436 drflac_cache_t resultHi;
3437
3438 bs->consumedBits += riceLength;
3439 bs->cache <<= setBitOffsetPlus1 & (DRFLAC_CACHE_L1_SIZE_BITS(bs)-1); /* <-- Equivalent to "if (setBitOffsetPlus1 < DRFLAC_CACHE_L1_SIZE_BITS(bs)) { bs->cache <<= setBitOffsetPlus1; }" */
3440
3441 /* 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. */
3442 bitCountLo = bs->consumedBits - DRFLAC_CACHE_L1_SIZE_BITS(bs);
3443 resultHi = DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, riceParam); /* <-- Use DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE() if ever this function allows riceParam=0. */
3444
3445 if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
3446#ifndef DR_FLAC_NO_CRC
3447 drflac__update_crc16(bs);
3448#endif
3449 bs->cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]);
3450 bs->consumedBits = 0;
3451#ifndef DR_FLAC_NO_CRC
3452 bs->crc16Cache = bs->cache;
3453#endif
3454 } else {
3455 /* Slow path. We need to fetch more data from the client. */
3456 if (!drflac__reload_cache(bs)) {
3457 return DRFLAC_FALSE;
3458 }
3459 if (bitCountLo > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
3460 /* This happens when we get to end of stream */
3461 return DRFLAC_FALSE;
3462 }
3463 }
3464
3465 riceParamPart = (drflac_uint32)(resultHi | DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE(bs, bitCountLo));
3466
3467 bs->consumedBits += bitCountLo;
3468 bs->cache <<= bitCountLo;
3469 }
3470
3471 pZeroCounterOut[0] = zeroCounter;
3472 pRiceParamPartOut[0] = riceParamPart;
3473
3474 return DRFLAC_TRUE;
3475}
3476#endif
3477
3478static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts_x1(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut)
3479{
3480 drflac_uint32 riceParamPlus1 = riceParam + 1;
3481 /*drflac_cache_t riceParamPlus1Mask = DRFLAC_CACHE_L1_SELECTION_MASK(riceParamPlus1);*/
3482 drflac_uint32 riceParamPlus1Shift = DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceParamPlus1);
3483 drflac_uint32 riceParamPlus1MaxConsumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceParamPlus1;
3484
3485 /*
3486 The idea here is to use local variables for the cache in an attempt to encourage the compiler to store them in registers. I have
3487 no idea how this will work in practice...
3488 */
3489 drflac_cache_t bs_cache = bs->cache;
3490 drflac_uint32 bs_consumedBits = bs->consumedBits;
3491
3492 /* The first thing to do is find the first unset bit. Most likely a bit will be set in the current cache line. */
3493 drflac_uint32 lzcount = drflac__clz(bs_cache);
3494 if (lzcount < sizeof(bs_cache)*8) {
3495 pZeroCounterOut[0] = lzcount;
3496
3497 /*
3498 It is most likely that the riceParam part (which comes after the zero counter) is also on this cache line. When extracting
3499 this, we include the set bit from the unary coded part because it simplifies cache management. This bit will be handled
3500 outside of this function at a higher level.
3501 */
3502 extract_rice_param_part:
3503 bs_cache <<= lzcount;
3504 bs_consumedBits += lzcount;
3505
3506 if (bs_consumedBits <= riceParamPlus1MaxConsumedBits) {
3507 /* Getting here means the rice parameter part is wholly contained within the current cache line. */
3508 pRiceParamPartOut[0] = (drflac_uint32)(bs_cache >> riceParamPlus1Shift);
3509 bs_cache <<= riceParamPlus1;
3510 bs_consumedBits += riceParamPlus1;
3511 } else {
3512 drflac_uint32 riceParamPartHi;
3513 drflac_uint32 riceParamPartLo;
3514 drflac_uint32 riceParamPartLoBitCount;
3515
3516 /*
3517 Getting here means the rice parameter part straddles the cache line. We need to read from the tail of the current cache
3518 line, reload the cache, and then combine it with the head of the next cache line.
3519 */
3520
3521 /* Grab the high part of the rice parameter part. */
3522 riceParamPartHi = (drflac_uint32)(bs_cache >> riceParamPlus1Shift);
3523
3524 /* Before reloading the cache we need to grab the size in bits of the low part. */
3525 riceParamPartLoBitCount = bs_consumedBits - riceParamPlus1MaxConsumedBits;
3526 DRFLAC_ASSERT(riceParamPartLoBitCount > 0 && riceParamPartLoBitCount < 32);
3527
3528 /* Now reload the cache. */
3529 if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
3530 #ifndef DR_FLAC_NO_CRC
3531 drflac__update_crc16(bs);
3532 #endif
3533 bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]);
3534 bs_consumedBits = riceParamPartLoBitCount;
3535 #ifndef DR_FLAC_NO_CRC
3536 bs->crc16Cache = bs_cache;
3537 #endif
3538 } else {
3539 /* Slow path. We need to fetch more data from the client. */
3540 if (!drflac__reload_cache(bs)) {
3541 return DRFLAC_FALSE;
3542 }
3543 if (riceParamPartLoBitCount > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
3544 /* This happens when we get to end of stream */
3545 return DRFLAC_FALSE;
3546 }
3547
3548 bs_cache = bs->cache;
3549 bs_consumedBits = bs->consumedBits + riceParamPartLoBitCount;
3550 }
3551
3552 /* We should now have enough information to construct the rice parameter part. */
3553 riceParamPartLo = (drflac_uint32)(bs_cache >> (DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceParamPartLoBitCount)));
3554 pRiceParamPartOut[0] = riceParamPartHi | riceParamPartLo;
3555
3556 bs_cache <<= riceParamPartLoBitCount;
3557 }
3558 } else {
3559 /*
3560 Getting here means there are no bits set on the cache line. This is a less optimal case because we just wasted a call
3561 to drflac__clz() and we need to reload the cache.
3562 */
3563 drflac_uint32 zeroCounter = (drflac_uint32)(DRFLAC_CACHE_L1_SIZE_BITS(bs) - bs_consumedBits);
3564 for (;;) {
3565 if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
3566 #ifndef DR_FLAC_NO_CRC
3567 drflac__update_crc16(bs);
3568 #endif
3569 bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]);
3570 bs_consumedBits = 0;
3571 #ifndef DR_FLAC_NO_CRC
3572 bs->crc16Cache = bs_cache;
3573 #endif
3574 } else {
3575 /* Slow path. We need to fetch more data from the client. */
3576 if (!drflac__reload_cache(bs)) {
3577 return DRFLAC_FALSE;
3578 }
3579
3580 bs_cache = bs->cache;
3581 bs_consumedBits = bs->consumedBits;
3582 }
3583
3584 lzcount = drflac__clz(bs_cache);
3585 zeroCounter += lzcount;
3586
3587 if (lzcount < sizeof(bs_cache)*8) {
3588 break;
3589 }
3590 }
3591
3592 pZeroCounterOut[0] = zeroCounter;
3593 goto extract_rice_param_part;
3594 }
3595
3596 /* Make sure the cache is restored at the end of it all. */
3597 bs->cache = bs_cache;
3598 bs->consumedBits = bs_consumedBits;
3599
3600 return DRFLAC_TRUE;
3601}
3602
3603static DRFLAC_INLINE drflac_bool32 drflac__seek_rice_parts(drflac_bs* bs, drflac_uint8 riceParam)
3604{
3605 drflac_uint32 riceParamPlus1 = riceParam + 1;
3606 drflac_uint32 riceParamPlus1MaxConsumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceParamPlus1;
3607
3608 /*
3609 The idea here is to use local variables for the cache in an attempt to encourage the compiler to store them in registers. I have
3610 no idea how this will work in practice...
3611 */
3612 drflac_cache_t bs_cache = bs->cache;
3613 drflac_uint32 bs_consumedBits = bs->consumedBits;
3614
3615 /* The first thing to do is find the first unset bit. Most likely a bit will be set in the current cache line. */
3616 drflac_uint32 lzcount = drflac__clz(bs_cache);
3617 if (lzcount < sizeof(bs_cache)*8) {
3618 /*
3619 It is most likely that the riceParam part (which comes after the zero counter) is also on this cache line. When extracting
3620 this, we include the set bit from the unary coded part because it simplifies cache management. This bit will be handled
3621 outside of this function at a higher level.
3622 */
3623 extract_rice_param_part:
3624 bs_cache <<= lzcount;
3625 bs_consumedBits += lzcount;
3626
3627 if (bs_consumedBits <= riceParamPlus1MaxConsumedBits) {
3628 /* Getting here means the rice parameter part is wholly contained within the current cache line. */
3629 bs_cache <<= riceParamPlus1;
3630 bs_consumedBits += riceParamPlus1;
3631 } else {
3632 /*
3633 Getting here means the rice parameter part straddles the cache line. We need to read from the tail of the current cache
3634 line, reload the cache, and then combine it with the head of the next cache line.
3635 */
3636
3637 /* Before reloading the cache we need to grab the size in bits of the low part. */
3638 drflac_uint32 riceParamPartLoBitCount = bs_consumedBits - riceParamPlus1MaxConsumedBits;
3639 DRFLAC_ASSERT(riceParamPartLoBitCount > 0 && riceParamPartLoBitCount < 32);
3640
3641 /* Now reload the cache. */
3642 if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
3643 #ifndef DR_FLAC_NO_CRC
3644 drflac__update_crc16(bs);
3645 #endif
3646 bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]);
3647 bs_consumedBits = riceParamPartLoBitCount;
3648 #ifndef DR_FLAC_NO_CRC
3649 bs->crc16Cache = bs_cache;
3650 #endif
3651 } else {
3652 /* Slow path. We need to fetch more data from the client. */
3653 if (!drflac__reload_cache(bs)) {
3654 return DRFLAC_FALSE;
3655 }
3656
3657 if (riceParamPartLoBitCount > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
3658 /* This happens when we get to end of stream */
3659 return DRFLAC_FALSE;
3660 }
3661
3662 bs_cache = bs->cache;
3663 bs_consumedBits = bs->consumedBits + riceParamPartLoBitCount;
3664 }
3665
3666 bs_cache <<= riceParamPartLoBitCount;
3667 }
3668 } else {
3669 /*
3670 Getting here means there are no bits set on the cache line. This is a less optimal case because we just wasted a call
3671 to drflac__clz() and we need to reload the cache.
3672 */
3673 for (;;) {
3674 if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
3675 #ifndef DR_FLAC_NO_CRC
3676 drflac__update_crc16(bs);
3677 #endif
3678 bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]);
3679 bs_consumedBits = 0;
3680 #ifndef DR_FLAC_NO_CRC
3681 bs->crc16Cache = bs_cache;
3682 #endif
3683 } else {
3684 /* Slow path. We need to fetch more data from the client. */
3685 if (!drflac__reload_cache(bs)) {
3686 return DRFLAC_FALSE;
3687 }
3688
3689 bs_cache = bs->cache;
3690 bs_consumedBits = bs->consumedBits;
3691 }
3692
3693 lzcount = drflac__clz(bs_cache);
3694 if (lzcount < sizeof(bs_cache)*8) {
3695 break;
3696 }
3697 }
3698
3699 goto extract_rice_param_part;
3700 }
3701
3702 /* Make sure the cache is restored at the end of it all. */
3703 bs->cache = bs_cache;
3704 bs->consumedBits = bs_consumedBits;
3705
3706 return DRFLAC_TRUE;
3707}
3708
3709
3710static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar_zeroorder(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
3711{
3712 drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
3713 drflac_uint32 zeroCountPart0;
3714 drflac_uint32 riceParamPart0;
3715 drflac_uint32 riceParamMask;
3716 drflac_uint32 i;
3717
3718 DRFLAC_ASSERT(bs != NULL);
3719 DRFLAC_ASSERT(pSamplesOut != NULL);
3720
3721 (void)bitsPerSample;
3722 (void)order;
3723 (void)shift;
3724 (void)coefficients;
3725
3726 riceParamMask = (drflac_uint32)~((~0UL) << riceParam);
3727
3728 i = 0;
3729 while (i < count) {
3730 /* Rice extraction. */
3731 if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0)) {
3732 return DRFLAC_FALSE;
3733 }
3734
3735 /* Rice reconstruction. */
3736 riceParamPart0 &= riceParamMask;
3737 riceParamPart0 |= (zeroCountPart0 << riceParam);
3738 riceParamPart0 = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01];
3739
3740 pSamplesOut[i] = riceParamPart0;
3741
3742 i += 1;
3743 }
3744
3745 return DRFLAC_TRUE;
3746}
3747
3748static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
3749{
3750 drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
3751 drflac_uint32 zeroCountPart0 = 0;
3752 drflac_uint32 zeroCountPart1 = 0;
3753 drflac_uint32 zeroCountPart2 = 0;
3754 drflac_uint32 zeroCountPart3 = 0;
3755 drflac_uint32 riceParamPart0 = 0;
3756 drflac_uint32 riceParamPart1 = 0;
3757 drflac_uint32 riceParamPart2 = 0;
3758 drflac_uint32 riceParamPart3 = 0;
3759 drflac_uint32 riceParamMask;
3760 const drflac_int32* pSamplesOutEnd;
3761 drflac_uint32 i;
3762
3763 DRFLAC_ASSERT(bs != NULL);
3764 DRFLAC_ASSERT(pSamplesOut != NULL);
3765
3766 if (lpcOrder == 0) {
3767 return drflac__decode_samples_with_residual__rice__scalar_zeroorder(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut);
3768 }
3769
3770 riceParamMask = (drflac_uint32)~((~0UL) << riceParam);
3771 pSamplesOutEnd = pSamplesOut + (count & ~3);
3772
3773 if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) {
3774 while (pSamplesOut < pSamplesOutEnd) {
3775 /*
3776 Rice extraction. It's faster to do this one at a time against local variables than it is to use the x4 version
3777 against an array. Not sure why, but perhaps it's making more efficient use of registers?
3778 */
3779 if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0) ||
3780 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart1, &riceParamPart1) ||
3781 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart2, &riceParamPart2) ||
3782 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart3, &riceParamPart3)) {
3783 return DRFLAC_FALSE;
3784 }
3785
3786 riceParamPart0 &= riceParamMask;
3787 riceParamPart1 &= riceParamMask;
3788 riceParamPart2 &= riceParamMask;
3789 riceParamPart3 &= riceParamMask;
3790
3791 riceParamPart0 |= (zeroCountPart0 << riceParam);
3792 riceParamPart1 |= (zeroCountPart1 << riceParam);
3793 riceParamPart2 |= (zeroCountPart2 << riceParam);
3794 riceParamPart3 |= (zeroCountPart3 << riceParam);
3795
3796 riceParamPart0 = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01];
3797 riceParamPart1 = (riceParamPart1 >> 1) ^ t[riceParamPart1 & 0x01];
3798 riceParamPart2 = (riceParamPart2 >> 1) ^ t[riceParamPart2 & 0x01];
3799 riceParamPart3 = (riceParamPart3 >> 1) ^ t[riceParamPart3 & 0x01];
3800
3801 pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 0);
3802 pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 1);
3803 pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 2);
3804 pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 3);
3805
3806 pSamplesOut += 4;
3807 }
3808 } else {
3809 while (pSamplesOut < pSamplesOutEnd) {
3810 if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0) ||
3811 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart1, &riceParamPart1) ||
3812 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart2, &riceParamPart2) ||
3813 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart3, &riceParamPart3)) {
3814 return DRFLAC_FALSE;
3815 }
3816
3817 riceParamPart0 &= riceParamMask;
3818 riceParamPart1 &= riceParamMask;
3819 riceParamPart2 &= riceParamMask;
3820 riceParamPart3 &= riceParamMask;
3821
3822 riceParamPart0 |= (zeroCountPart0 << riceParam);
3823 riceParamPart1 |= (zeroCountPart1 << riceParam);
3824 riceParamPart2 |= (zeroCountPart2 << riceParam);
3825 riceParamPart3 |= (zeroCountPart3 << riceParam);
3826
3827 riceParamPart0 = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01];
3828 riceParamPart1 = (riceParamPart1 >> 1) ^ t[riceParamPart1 & 0x01];
3829 riceParamPart2 = (riceParamPart2 >> 1) ^ t[riceParamPart2 & 0x01];
3830 riceParamPart3 = (riceParamPart3 >> 1) ^ t[riceParamPart3 & 0x01];
3831
3832 pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 0);
3833 pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 1);
3834 pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 2);
3835 pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 3);
3836
3837 pSamplesOut += 4;
3838 }
3839 }
3840
3841 i = (count & ~3);
3842 while (i < count) {
3843 /* Rice extraction. */
3844 if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0)) {
3845 return DRFLAC_FALSE;
3846 }
3847
3848 /* Rice reconstruction. */
3849 riceParamPart0 &= riceParamMask;
3850 riceParamPart0 |= (zeroCountPart0 << riceParam);
3851 riceParamPart0 = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01];
3852 /*riceParamPart0 = (riceParamPart0 >> 1) ^ (~(riceParamPart0 & 0x01) + 1);*/
3853
3854 /* Sample reconstruction. */
3855 if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) {
3856 pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 0);
3857 } else {
3858 pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 0);
3859 }
3860
3861 i += 1;
3862 pSamplesOut += 1;
3863 }
3864
3865 return DRFLAC_TRUE;
3866}
3867
3868#if defined(DRFLAC_SUPPORT_SSE2)
3869static DRFLAC_INLINE __m128i drflac__mm_packs_interleaved_epi32(__m128i a, __m128i b)
3870{
3871 __m128i r;
3872
3873 /* Pack. */
3874 r = _mm_packs_epi32(a, b);
3875
3876 /* a3a2 a1a0 b3b2 b1b0 -> a3a2 b3b2 a1a0 b1b0 */
3877 r = _mm_shuffle_epi32(r, _MM_SHUFFLE(3, 1, 2, 0));
3878
3879 /* a3a2 b3b2 a1a0 b1b0 -> a3b3 a2b2 a1b1 a0b0 */
3880 r = _mm_shufflehi_epi16(r, _MM_SHUFFLE(3, 1, 2, 0));
3881 r = _mm_shufflelo_epi16(r, _MM_SHUFFLE(3, 1, 2, 0));
3882
3883 return r;
3884}
3885#endif
3886
3887#if defined(DRFLAC_SUPPORT_SSE41)
3888static DRFLAC_INLINE __m128i drflac__mm_not_si128(__m128i a)
3889{
3890 return _mm_xor_si128(a, _mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128()));
3891}
3892
3893static DRFLAC_INLINE __m128i drflac__mm_hadd_epi32(__m128i x)
3894{
3895 __m128i x64 = _mm_add_epi32(x, _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2)));
3896 __m128i x32 = _mm_shufflelo_epi16(x64, _MM_SHUFFLE(1, 0, 3, 2));
3897 return _mm_add_epi32(x64, x32);
3898}
3899
3900static DRFLAC_INLINE __m128i drflac__mm_hadd_epi64(__m128i x)
3901{
3902 return _mm_add_epi64(x, _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2)));
3903}
3904
3905static DRFLAC_INLINE __m128i drflac__mm_srai_epi64(__m128i x, int count)
3906{
3907 /*
3908 To simplify this we are assuming count < 32. This restriction allows us to work on a low side and a high side. The low side
3909 is shifted with zero bits, whereas the right side is shifted with sign bits.
3910 */
3911 __m128i lo = _mm_srli_epi64(x, count);
3912 __m128i hi = _mm_srai_epi32(x, count);
3913
3914 hi = _mm_and_si128(hi, _mm_set_epi32(0xFFFFFFFF, 0, 0xFFFFFFFF, 0)); /* The high part needs to have the low part cleared. */
3915
3916 return _mm_or_si128(lo, hi);
3917}
3918
3919static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41_32(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
3920{
3921 int i;
3922 drflac_uint32 riceParamMask;
3923 drflac_int32* pDecodedSamples = pSamplesOut;
3924 drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3);
3925 drflac_uint32 zeroCountParts0 = 0;
3926 drflac_uint32 zeroCountParts1 = 0;
3927 drflac_uint32 zeroCountParts2 = 0;
3928 drflac_uint32 zeroCountParts3 = 0;
3929 drflac_uint32 riceParamParts0 = 0;
3930 drflac_uint32 riceParamParts1 = 0;
3931 drflac_uint32 riceParamParts2 = 0;
3932 drflac_uint32 riceParamParts3 = 0;
3933 __m128i coefficients128_0;
3934 __m128i coefficients128_4;
3935 __m128i coefficients128_8;
3936 __m128i samples128_0;
3937 __m128i samples128_4;
3938 __m128i samples128_8;
3939 __m128i riceParamMask128;
3940
3941 const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
3942
3943 riceParamMask = (drflac_uint32)~((~0UL) << riceParam);
3944 riceParamMask128 = _mm_set1_epi32(riceParamMask);
3945
3946 /* Pre-load. */
3947 coefficients128_0 = _mm_setzero_si128();
3948 coefficients128_4 = _mm_setzero_si128();
3949 coefficients128_8 = _mm_setzero_si128();
3950
3951 samples128_0 = _mm_setzero_si128();
3952 samples128_4 = _mm_setzero_si128();
3953 samples128_8 = _mm_setzero_si128();
3954
3955 /*
3956 Pre-loading the coefficients and prior samples is annoying because we need to ensure we don't try reading more than
3957 what's available in the input buffers. It would be convenient to use a fall-through switch to do this, but this results
3958 in strict aliasing warnings with GCC. To work around this I'm just doing something hacky. This feels a bit convoluted
3959 so I think there's opportunity for this to be simplified.
3960 */
3961#if 1
3962 {
3963 int runningOrder = order;
3964
3965 /* 0 - 3. */
3966 if (runningOrder >= 4) {
3967 coefficients128_0 = _mm_loadu_si128((const __m128i*)(coefficients + 0));
3968 samples128_0 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 4));
3969 runningOrder -= 4;
3970 } else {
3971 switch (runningOrder) {
3972 case 3: coefficients128_0 = _mm_set_epi32(0, coefficients[2], coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], pSamplesOut[-3], 0); break;
3973 case 2: coefficients128_0 = _mm_set_epi32(0, 0, coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], 0, 0); break;
3974 case 1: coefficients128_0 = _mm_set_epi32(0, 0, 0, coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], 0, 0, 0); break;
3975 }
3976 runningOrder = 0;
3977 }
3978
3979 /* 4 - 7 */
3980 if (runningOrder >= 4) {
3981 coefficients128_4 = _mm_loadu_si128((const __m128i*)(coefficients + 4));
3982 samples128_4 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 8));
3983 runningOrder -= 4;
3984 } else {
3985 switch (runningOrder) {
3986 case 3: coefficients128_4 = _mm_set_epi32(0, coefficients[6], coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], pSamplesOut[-7], 0); break;
3987 case 2: coefficients128_4 = _mm_set_epi32(0, 0, coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], 0, 0); break;
3988 case 1: coefficients128_4 = _mm_set_epi32(0, 0, 0, coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], 0, 0, 0); break;
3989 }
3990 runningOrder = 0;
3991 }
3992
3993 /* 8 - 11 */
3994 if (runningOrder == 4) {
3995 coefficients128_8 = _mm_loadu_si128((const __m128i*)(coefficients + 8));
3996 samples128_8 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 12));
3997 runningOrder -= 4;
3998 } else {
3999 switch (runningOrder) {
4000 case 3: coefficients128_8 = _mm_set_epi32(0, coefficients[10], coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], pSamplesOut[-11], 0); break;
4001 case 2: coefficients128_8 = _mm_set_epi32(0, 0, coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], 0, 0); break;
4002 case 1: coefficients128_8 = _mm_set_epi32(0, 0, 0, coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], 0, 0, 0); break;
4003 }
4004 runningOrder = 0;
4005 }
4006
4007 /* Coefficients need to be shuffled for our streaming algorithm below to work. Samples are already in the correct order from the loading routine above. */
4008 coefficients128_0 = _mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(0, 1, 2, 3));
4009 coefficients128_4 = _mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(0, 1, 2, 3));
4010 coefficients128_8 = _mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(0, 1, 2, 3));
4011 }
4012#else
4013 /* This causes strict-aliasing warnings with GCC. */
4014 switch (order)
4015 {
4016 case 12: ((drflac_int32*)&coefficients128_8)[0] = coefficients[11]; ((drflac_int32*)&samples128_8)[0] = pDecodedSamples[-12];
4017 case 11: ((drflac_int32*)&coefficients128_8)[1] = coefficients[10]; ((drflac_int32*)&samples128_8)[1] = pDecodedSamples[-11];
4018 case 10: ((drflac_int32*)&coefficients128_8)[2] = coefficients[ 9]; ((drflac_int32*)&samples128_8)[2] = pDecodedSamples[-10];
4019 case 9: ((drflac_int32*)&coefficients128_8)[3] = coefficients[ 8]; ((drflac_int32*)&samples128_8)[3] = pDecodedSamples[- 9];
4020 case 8: ((drflac_int32*)&coefficients128_4)[0] = coefficients[ 7]; ((drflac_int32*)&samples128_4)[0] = pDecodedSamples[- 8];
4021 case 7: ((drflac_int32*)&coefficients128_4)[1] = coefficients[ 6]; ((drflac_int32*)&samples128_4)[1] = pDecodedSamples[- 7];
4022 case 6: ((drflac_int32*)&coefficients128_4)[2] = coefficients[ 5]; ((drflac_int32*)&samples128_4)[2] = pDecodedSamples[- 6];
4023 case 5: ((drflac_int32*)&coefficients128_4)[3] = coefficients[ 4]; ((drflac_int32*)&samples128_4)[3] = pDecodedSamples[- 5];
4024 case 4: ((drflac_int32*)&coefficients128_0)[0] = coefficients[ 3]; ((drflac_int32*)&samples128_0)[0] = pDecodedSamples[- 4];
4025 case 3: ((drflac_int32*)&coefficients128_0)[1] = coefficients[ 2]; ((drflac_int32*)&samples128_0)[1] = pDecodedSamples[- 3];
4026 case 2: ((drflac_int32*)&coefficients128_0)[2] = coefficients[ 1]; ((drflac_int32*)&samples128_0)[2] = pDecodedSamples[- 2];
4027 case 1: ((drflac_int32*)&coefficients128_0)[3] = coefficients[ 0]; ((drflac_int32*)&samples128_0)[3] = pDecodedSamples[- 1];
4028 }
4029#endif
4030
4031 /* For this version we are doing one sample at a time. */
4032 while (pDecodedSamples < pDecodedSamplesEnd) {
4033 __m128i prediction128;
4034 __m128i zeroCountPart128;
4035 __m128i riceParamPart128;
4036
4037 if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0) ||
4038 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts1, &riceParamParts1) ||
4039 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts2, &riceParamParts2) ||
4040 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts3, &riceParamParts3)) {
4041 return DRFLAC_FALSE;
4042 }
4043
4044 zeroCountPart128 = _mm_set_epi32(zeroCountParts3, zeroCountParts2, zeroCountParts1, zeroCountParts0);
4045 riceParamPart128 = _mm_set_epi32(riceParamParts3, riceParamParts2, riceParamParts1, riceParamParts0);
4046
4047 riceParamPart128 = _mm_and_si128(riceParamPart128, riceParamMask128);
4048 riceParamPart128 = _mm_or_si128(riceParamPart128, _mm_slli_epi32(zeroCountPart128, riceParam));
4049 riceParamPart128 = _mm_xor_si128(_mm_srli_epi32(riceParamPart128, 1), _mm_add_epi32(drflac__mm_not_si128(_mm_and_si128(riceParamPart128, _mm_set1_epi32(0x01))), _mm_set1_epi32(0x01))); /* <-- SSE2 compatible */
4050 /*riceParamPart128 = _mm_xor_si128(_mm_srli_epi32(riceParamPart128, 1), _mm_mullo_epi32(_mm_and_si128(riceParamPart128, _mm_set1_epi32(0x01)), _mm_set1_epi32(0xFFFFFFFF)));*/ /* <-- Only supported from SSE4.1 and is slower in my testing... */
4051
4052 if (order <= 4) {
4053 for (i = 0; i < 4; i += 1) {
4054 prediction128 = _mm_mullo_epi32(coefficients128_0, samples128_0);
4055
4056 /* Horizontal add and shift. */
4057 prediction128 = drflac__mm_hadd_epi32(prediction128);
4058 prediction128 = _mm_srai_epi32(prediction128, shift);
4059 prediction128 = _mm_add_epi32(riceParamPart128, prediction128);
4060
4061 samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4);
4062 riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4);
4063 }
4064 } else if (order <= 8) {
4065 for (i = 0; i < 4; i += 1) {
4066 prediction128 = _mm_mullo_epi32(coefficients128_4, samples128_4);
4067 prediction128 = _mm_add_epi32(prediction128, _mm_mullo_epi32(coefficients128_0, samples128_0));
4068
4069 /* Horizontal add and shift. */
4070 prediction128 = drflac__mm_hadd_epi32(prediction128);
4071 prediction128 = _mm_srai_epi32(prediction128, shift);
4072 prediction128 = _mm_add_epi32(riceParamPart128, prediction128);
4073
4074 samples128_4 = _mm_alignr_epi8(samples128_0, samples128_4, 4);
4075 samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4);
4076 riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4);
4077 }
4078 } else {
4079 for (i = 0; i < 4; i += 1) {
4080 prediction128 = _mm_mullo_epi32(coefficients128_8, samples128_8);
4081 prediction128 = _mm_add_epi32(prediction128, _mm_mullo_epi32(coefficients128_4, samples128_4));
4082 prediction128 = _mm_add_epi32(prediction128, _mm_mullo_epi32(coefficients128_0, samples128_0));
4083
4084 /* Horizontal add and shift. */
4085 prediction128 = drflac__mm_hadd_epi32(prediction128);
4086 prediction128 = _mm_srai_epi32(prediction128, shift);
4087 prediction128 = _mm_add_epi32(riceParamPart128, prediction128);
4088
4089 samples128_8 = _mm_alignr_epi8(samples128_4, samples128_8, 4);
4090 samples128_4 = _mm_alignr_epi8(samples128_0, samples128_4, 4);
4091 samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4);
4092 riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4);
4093 }
4094 }
4095
4096 /* We store samples in groups of 4. */
4097 _mm_storeu_si128((__m128i*)pDecodedSamples, samples128_0);
4098 pDecodedSamples += 4;
4099 }
4100
4101 /* Make sure we process the last few samples. */
4102 i = (count & ~3);
4103 while (i < (int)count) {
4104 /* Rice extraction. */
4105 if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0)) {
4106 return DRFLAC_FALSE;
4107 }
4108
4109 /* Rice reconstruction. */
4110 riceParamParts0 &= riceParamMask;
4111 riceParamParts0 |= (zeroCountParts0 << riceParam);
4112 riceParamParts0 = (riceParamParts0 >> 1) ^ t[riceParamParts0 & 0x01];
4113
4114 /* Sample reconstruction. */
4115 pDecodedSamples[0] = riceParamParts0 + drflac__calculate_prediction_32(order, shift, coefficients, pDecodedSamples);
4116
4117 i += 1;
4118 pDecodedSamples += 1;
4119 }
4120
4121 return DRFLAC_TRUE;
4122}
4123
4124static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41_64(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
4125{
4126 int i;
4127 drflac_uint32 riceParamMask;
4128 drflac_int32* pDecodedSamples = pSamplesOut;
4129 drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3);
4130 drflac_uint32 zeroCountParts0 = 0;
4131 drflac_uint32 zeroCountParts1 = 0;
4132 drflac_uint32 zeroCountParts2 = 0;
4133 drflac_uint32 zeroCountParts3 = 0;
4134 drflac_uint32 riceParamParts0 = 0;
4135 drflac_uint32 riceParamParts1 = 0;
4136 drflac_uint32 riceParamParts2 = 0;
4137 drflac_uint32 riceParamParts3 = 0;
4138 __m128i coefficients128_0;
4139 __m128i coefficients128_4;
4140 __m128i coefficients128_8;
4141 __m128i samples128_0;
4142 __m128i samples128_4;
4143 __m128i samples128_8;
4144 __m128i prediction128;
4145 __m128i riceParamMask128;
4146
4147 const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
4148
4149 DRFLAC_ASSERT(order <= 12);
4150
4151 riceParamMask = (drflac_uint32)~((~0UL) << riceParam);
4152 riceParamMask128 = _mm_set1_epi32(riceParamMask);
4153
4154 prediction128 = _mm_setzero_si128();
4155
4156 /* Pre-load. */
4157 coefficients128_0 = _mm_setzero_si128();
4158 coefficients128_4 = _mm_setzero_si128();
4159 coefficients128_8 = _mm_setzero_si128();
4160
4161 samples128_0 = _mm_setzero_si128();
4162 samples128_4 = _mm_setzero_si128();
4163 samples128_8 = _mm_setzero_si128();
4164
4165#if 1
4166 {
4167 int runningOrder = order;
4168
4169 /* 0 - 3. */
4170 if (runningOrder >= 4) {
4171 coefficients128_0 = _mm_loadu_si128((const __m128i*)(coefficients + 0));
4172 samples128_0 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 4));
4173 runningOrder -= 4;
4174 } else {
4175 switch (runningOrder) {
4176 case 3: coefficients128_0 = _mm_set_epi32(0, coefficients[2], coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], pSamplesOut[-3], 0); break;
4177 case 2: coefficients128_0 = _mm_set_epi32(0, 0, coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], 0, 0); break;
4178 case 1: coefficients128_0 = _mm_set_epi32(0, 0, 0, coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], 0, 0, 0); break;
4179 }
4180 runningOrder = 0;
4181 }
4182
4183 /* 4 - 7 */
4184 if (runningOrder >= 4) {
4185 coefficients128_4 = _mm_loadu_si128((const __m128i*)(coefficients + 4));
4186 samples128_4 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 8));
4187 runningOrder -= 4;
4188 } else {
4189 switch (runningOrder) {
4190 case 3: coefficients128_4 = _mm_set_epi32(0, coefficients[6], coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], pSamplesOut[-7], 0); break;
4191 case 2: coefficients128_4 = _mm_set_epi32(0, 0, coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], 0, 0); break;
4192 case 1: coefficients128_4 = _mm_set_epi32(0, 0, 0, coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], 0, 0, 0); break;
4193 }
4194 runningOrder = 0;
4195 }
4196
4197 /* 8 - 11 */
4198 if (runningOrder == 4) {
4199 coefficients128_8 = _mm_loadu_si128((const __m128i*)(coefficients + 8));
4200 samples128_8 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 12));
4201 runningOrder -= 4;
4202 } else {
4203 switch (runningOrder) {
4204 case 3: coefficients128_8 = _mm_set_epi32(0, coefficients[10], coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], pSamplesOut[-11], 0); break;
4205 case 2: coefficients128_8 = _mm_set_epi32(0, 0, coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], 0, 0); break;
4206 case 1: coefficients128_8 = _mm_set_epi32(0, 0, 0, coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], 0, 0, 0); break;
4207 }
4208 runningOrder = 0;
4209 }
4210
4211 /* Coefficients need to be shuffled for our streaming algorithm below to work. Samples are already in the correct order from the loading routine above. */
4212 coefficients128_0 = _mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(0, 1, 2, 3));
4213 coefficients128_4 = _mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(0, 1, 2, 3));
4214 coefficients128_8 = _mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(0, 1, 2, 3));
4215 }
4216#else
4217 switch (order)
4218 {
4219 case 12: ((drflac_int32*)&coefficients128_8)[0] = coefficients[11]; ((drflac_int32*)&samples128_8)[0] = pDecodedSamples[-12];
4220 case 11: ((drflac_int32*)&coefficients128_8)[1] = coefficients[10]; ((drflac_int32*)&samples128_8)[1] = pDecodedSamples[-11];
4221 case 10: ((drflac_int32*)&coefficients128_8)[2] = coefficients[ 9]; ((drflac_int32*)&samples128_8)[2] = pDecodedSamples[-10];
4222 case 9: ((drflac_int32*)&coefficients128_8)[3] = coefficients[ 8]; ((drflac_int32*)&samples128_8)[3] = pDecodedSamples[- 9];
4223 case 8: ((drflac_int32*)&coefficients128_4)[0] = coefficients[ 7]; ((drflac_int32*)&samples128_4)[0] = pDecodedSamples[- 8];
4224 case 7: ((drflac_int32*)&coefficients128_4)[1] = coefficients[ 6]; ((drflac_int32*)&samples128_4)[1] = pDecodedSamples[- 7];
4225 case 6: ((drflac_int32*)&coefficients128_4)[2] = coefficients[ 5]; ((drflac_int32*)&samples128_4)[2] = pDecodedSamples[- 6];
4226 case 5: ((drflac_int32*)&coefficients128_4)[3] = coefficients[ 4]; ((drflac_int32*)&samples128_4)[3] = pDecodedSamples[- 5];
4227 case 4: ((drflac_int32*)&coefficients128_0)[0] = coefficients[ 3]; ((drflac_int32*)&samples128_0)[0] = pDecodedSamples[- 4];
4228 case 3: ((drflac_int32*)&coefficients128_0)[1] = coefficients[ 2]; ((drflac_int32*)&samples128_0)[1] = pDecodedSamples[- 3];
4229 case 2: ((drflac_int32*)&coefficients128_0)[2] = coefficients[ 1]; ((drflac_int32*)&samples128_0)[2] = pDecodedSamples[- 2];
4230 case 1: ((drflac_int32*)&coefficients128_0)[3] = coefficients[ 0]; ((drflac_int32*)&samples128_0)[3] = pDecodedSamples[- 1];
4231 }
4232#endif
4233
4234 /* For this version we are doing one sample at a time. */
4235 while (pDecodedSamples < pDecodedSamplesEnd) {
4236 __m128i zeroCountPart128;
4237 __m128i riceParamPart128;
4238
4239 if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0) ||
4240 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts1, &riceParamParts1) ||
4241 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts2, &riceParamParts2) ||
4242 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts3, &riceParamParts3)) {
4243 return DRFLAC_FALSE;
4244 }
4245
4246 zeroCountPart128 = _mm_set_epi32(zeroCountParts3, zeroCountParts2, zeroCountParts1, zeroCountParts0);
4247 riceParamPart128 = _mm_set_epi32(riceParamParts3, riceParamParts2, riceParamParts1, riceParamParts0);
4248
4249 riceParamPart128 = _mm_and_si128(riceParamPart128, riceParamMask128);
4250 riceParamPart128 = _mm_or_si128(riceParamPart128, _mm_slli_epi32(zeroCountPart128, riceParam));
4251 riceParamPart128 = _mm_xor_si128(_mm_srli_epi32(riceParamPart128, 1), _mm_add_epi32(drflac__mm_not_si128(_mm_and_si128(riceParamPart128, _mm_set1_epi32(1))), _mm_set1_epi32(1)));
4252
4253 for (i = 0; i < 4; i += 1) {
4254 prediction128 = _mm_xor_si128(prediction128, prediction128); /* Reset to 0. */
4255
4256 switch (order)
4257 {
4258 case 12:
4259 case 11: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(1, 1, 0, 0)), _mm_shuffle_epi32(samples128_8, _MM_SHUFFLE(1, 1, 0, 0))));
4260 case 10:
4261 case 9: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(3, 3, 2, 2)), _mm_shuffle_epi32(samples128_8, _MM_SHUFFLE(3, 3, 2, 2))));
4262 case 8:
4263 case 7: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(1, 1, 0, 0)), _mm_shuffle_epi32(samples128_4, _MM_SHUFFLE(1, 1, 0, 0))));
4264 case 6:
4265 case 5: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(3, 3, 2, 2)), _mm_shuffle_epi32(samples128_4, _MM_SHUFFLE(3, 3, 2, 2))));
4266 case 4:
4267 case 3: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(1, 1, 0, 0)), _mm_shuffle_epi32(samples128_0, _MM_SHUFFLE(1, 1, 0, 0))));
4268 case 2:
4269 case 1: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(3, 3, 2, 2)), _mm_shuffle_epi32(samples128_0, _MM_SHUFFLE(3, 3, 2, 2))));
4270 }
4271
4272 /* Horizontal add and shift. */
4273 prediction128 = drflac__mm_hadd_epi64(prediction128);
4274 prediction128 = drflac__mm_srai_epi64(prediction128, shift);
4275 prediction128 = _mm_add_epi32(riceParamPart128, prediction128);
4276
4277 /* Our value should be sitting in prediction128[0]. We need to combine this with our SSE samples. */
4278 samples128_8 = _mm_alignr_epi8(samples128_4, samples128_8, 4);
4279 samples128_4 = _mm_alignr_epi8(samples128_0, samples128_4, 4);
4280 samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4);
4281
4282 /* Slide our rice parameter down so that the value in position 0 contains the next one to process. */
4283 riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4);
4284 }
4285
4286 /* We store samples in groups of 4. */
4287 _mm_storeu_si128((__m128i*)pDecodedSamples, samples128_0);
4288 pDecodedSamples += 4;
4289 }
4290
4291 /* Make sure we process the last few samples. */
4292 i = (count & ~3);
4293 while (i < (int)count) {
4294 /* Rice extraction. */
4295 if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0)) {
4296 return DRFLAC_FALSE;
4297 }
4298
4299 /* Rice reconstruction. */
4300 riceParamParts0 &= riceParamMask;
4301 riceParamParts0 |= (zeroCountParts0 << riceParam);
4302 riceParamParts0 = (riceParamParts0 >> 1) ^ t[riceParamParts0 & 0x01];
4303
4304 /* Sample reconstruction. */
4305 pDecodedSamples[0] = riceParamParts0 + drflac__calculate_prediction_64(order, shift, coefficients, pDecodedSamples);
4306
4307 i += 1;
4308 pDecodedSamples += 1;
4309 }
4310
4311 return DRFLAC_TRUE;
4312}
4313
4314static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
4315{
4316 DRFLAC_ASSERT(bs != NULL);
4317 DRFLAC_ASSERT(pSamplesOut != NULL);
4318
4319 /* In my testing the order is rarely > 12, so in this case I'm going to simplify the SSE implementation by only handling order <= 12. */
4320 if (lpcOrder > 0 && lpcOrder <= 12) {
4321 if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) {
4322 return drflac__decode_samples_with_residual__rice__sse41_64(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut);
4323 } else {
4324 return drflac__decode_samples_with_residual__rice__sse41_32(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut);
4325 }
4326 } else {
4327 return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut);
4328 }
4329}
4330#endif
4331
4332#if defined(DRFLAC_SUPPORT_NEON)
4333static DRFLAC_INLINE void drflac__vst2q_s32(drflac_int32* p, int32x4x2_t x)
4334{
4335 vst1q_s32(p+0, x.val[0]);
4336 vst1q_s32(p+4, x.val[1]);
4337}
4338
4339static DRFLAC_INLINE void drflac__vst2q_u32(drflac_uint32* p, uint32x4x2_t x)
4340{
4341 vst1q_u32(p+0, x.val[0]);
4342 vst1q_u32(p+4, x.val[1]);
4343}
4344
4345static DRFLAC_INLINE void drflac__vst2q_f32(float* p, float32x4x2_t x)
4346{
4347 vst1q_f32(p+0, x.val[0]);
4348 vst1q_f32(p+4, x.val[1]);
4349}
4350
4351static DRFLAC_INLINE void drflac__vst2q_s16(drflac_int16* p, int16x4x2_t x)
4352{
4353 vst1q_s16(p, vcombine_s16(x.val[0], x.val[1]));
4354}
4355
4356static DRFLAC_INLINE void drflac__vst2q_u16(drflac_uint16* p, uint16x4x2_t x)
4357{
4358 vst1q_u16(p, vcombine_u16(x.val[0], x.val[1]));
4359}
4360
4361static DRFLAC_INLINE int32x4_t drflac__vdupq_n_s32x4(drflac_int32 x3, drflac_int32 x2, drflac_int32 x1, drflac_int32 x0)
4362{
4363 drflac_int32 x[4];
4364 x[3] = x3;
4365 x[2] = x2;
4366 x[1] = x1;
4367 x[0] = x0;
4368 return vld1q_s32(x);
4369}
4370
4371static DRFLAC_INLINE int32x4_t drflac__valignrq_s32_1(int32x4_t a, int32x4_t b)
4372{
4373 /* Equivalent to SSE's _mm_alignr_epi8(a, b, 4) */
4374
4375 /* Reference */
4376 /*return drflac__vdupq_n_s32x4(
4377 vgetq_lane_s32(a, 0),
4378 vgetq_lane_s32(b, 3),
4379 vgetq_lane_s32(b, 2),
4380 vgetq_lane_s32(b, 1)
4381 );*/
4382
4383 return vextq_s32(b, a, 1);
4384}
4385
4386static DRFLAC_INLINE uint32x4_t drflac__valignrq_u32_1(uint32x4_t a, uint32x4_t b)
4387{
4388 /* Equivalent to SSE's _mm_alignr_epi8(a, b, 4) */
4389
4390 /* Reference */
4391 /*return drflac__vdupq_n_s32x4(
4392 vgetq_lane_s32(a, 0),
4393 vgetq_lane_s32(b, 3),
4394 vgetq_lane_s32(b, 2),
4395 vgetq_lane_s32(b, 1)
4396 );*/
4397
4398 return vextq_u32(b, a, 1);
4399}
4400
4401static DRFLAC_INLINE int32x2_t drflac__vhaddq_s32(int32x4_t x)
4402{
4403 /* The sum must end up in position 0. */
4404
4405 /* Reference */
4406 /*return vdupq_n_s32(
4407 vgetq_lane_s32(x, 3) +
4408 vgetq_lane_s32(x, 2) +
4409 vgetq_lane_s32(x, 1) +
4410 vgetq_lane_s32(x, 0)
4411 );*/
4412
4413 int32x2_t r = vadd_s32(vget_high_s32(x), vget_low_s32(x));
4414 return vpadd_s32(r, r);
4415}
4416
4417static DRFLAC_INLINE int64x1_t drflac__vhaddq_s64(int64x2_t x)
4418{
4419 return vadd_s64(vget_high_s64(x), vget_low_s64(x));
4420}
4421
4422static DRFLAC_INLINE int32x4_t drflac__vrevq_s32(int32x4_t x)
4423{
4424 /* Reference */
4425 /*return drflac__vdupq_n_s32x4(
4426 vgetq_lane_s32(x, 0),
4427 vgetq_lane_s32(x, 1),
4428 vgetq_lane_s32(x, 2),
4429 vgetq_lane_s32(x, 3)
4430 );*/
4431
4432 return vrev64q_s32(vcombine_s32(vget_high_s32(x), vget_low_s32(x)));
4433}
4434
4435static DRFLAC_INLINE int32x4_t drflac__vnotq_s32(int32x4_t x)
4436{
4437 return veorq_s32(x, vdupq_n_s32(0xFFFFFFFF));
4438}
4439
4440static DRFLAC_INLINE uint32x4_t drflac__vnotq_u32(uint32x4_t x)
4441{
4442 return veorq_u32(x, vdupq_n_u32(0xFFFFFFFF));
4443}
4444
4445static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_32(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
4446{
4447 int i;
4448 drflac_uint32 riceParamMask;
4449 drflac_int32* pDecodedSamples = pSamplesOut;
4450 drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3);
4451 drflac_uint32 zeroCountParts[4];
4452 drflac_uint32 riceParamParts[4];
4453 int32x4_t coefficients128_0;
4454 int32x4_t coefficients128_4;
4455 int32x4_t coefficients128_8;
4456 int32x4_t samples128_0;
4457 int32x4_t samples128_4;
4458 int32x4_t samples128_8;
4459 uint32x4_t riceParamMask128;
4460 int32x4_t riceParam128;
4461 int32x2_t shift64;
4462 uint32x4_t one128;
4463
4464 const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
4465
4466 riceParamMask = (drflac_uint32)~((~0UL) << riceParam);
4467 riceParamMask128 = vdupq_n_u32(riceParamMask);
4468
4469 riceParam128 = vdupq_n_s32(riceParam);
4470 shift64 = vdup_n_s32(-shift); /* Negate the shift because we'll be doing a variable shift using vshlq_s32(). */
4471 one128 = vdupq_n_u32(1);
4472
4473 /*
4474 Pre-loading the coefficients and prior samples is annoying because we need to ensure we don't try reading more than
4475 what's available in the input buffers. It would be conenient to use a fall-through switch to do this, but this results
4476 in strict aliasing warnings with GCC. To work around this I'm just doing something hacky. This feels a bit convoluted
4477 so I think there's opportunity for this to be simplified.
4478 */
4479 {
4480 int runningOrder = order;
4481 drflac_int32 tempC[4] = {0, 0, 0, 0};
4482 drflac_int32 tempS[4] = {0, 0, 0, 0};
4483
4484 /* 0 - 3. */
4485 if (runningOrder >= 4) {
4486 coefficients128_0 = vld1q_s32(coefficients + 0);
4487 samples128_0 = vld1q_s32(pSamplesOut - 4);
4488 runningOrder -= 4;
4489 } else {
4490 switch (runningOrder) {
4491 case 3: tempC[2] = coefficients[2]; tempS[1] = pSamplesOut[-3]; /* fallthrough */
4492 case 2: tempC[1] = coefficients[1]; tempS[2] = pSamplesOut[-2]; /* fallthrough */
4493 case 1: tempC[0] = coefficients[0]; tempS[3] = pSamplesOut[-1]; /* fallthrough */
4494 }
4495
4496 coefficients128_0 = vld1q_s32(tempC);
4497 samples128_0 = vld1q_s32(tempS);
4498 runningOrder = 0;
4499 }
4500
4501 /* 4 - 7 */
4502 if (runningOrder >= 4) {
4503 coefficients128_4 = vld1q_s32(coefficients + 4);
4504 samples128_4 = vld1q_s32(pSamplesOut - 8);
4505 runningOrder -= 4;
4506 } else {
4507 switch (runningOrder) {
4508 case 3: tempC[2] = coefficients[6]; tempS[1] = pSamplesOut[-7]; /* fallthrough */
4509 case 2: tempC[1] = coefficients[5]; tempS[2] = pSamplesOut[-6]; /* fallthrough */
4510 case 1: tempC[0] = coefficients[4]; tempS[3] = pSamplesOut[-5]; /* fallthrough */
4511 }
4512
4513 coefficients128_4 = vld1q_s32(tempC);
4514 samples128_4 = vld1q_s32(tempS);
4515 runningOrder = 0;
4516 }
4517
4518 /* 8 - 11 */
4519 if (runningOrder == 4) {
4520 coefficients128_8 = vld1q_s32(coefficients + 8);
4521 samples128_8 = vld1q_s32(pSamplesOut - 12);
4522 runningOrder -= 4;
4523 } else {
4524 switch (runningOrder) {
4525 case 3: tempC[2] = coefficients[10]; tempS[1] = pSamplesOut[-11]; /* fallthrough */
4526 case 2: tempC[1] = coefficients[ 9]; tempS[2] = pSamplesOut[-10]; /* fallthrough */
4527 case 1: tempC[0] = coefficients[ 8]; tempS[3] = pSamplesOut[- 9]; /* fallthrough */
4528 }
4529
4530 coefficients128_8 = vld1q_s32(tempC);
4531 samples128_8 = vld1q_s32(tempS);
4532 runningOrder = 0;
4533 }
4534
4535 /* Coefficients need to be shuffled for our streaming algorithm below to work. Samples are already in the correct order from the loading routine above. */
4536 coefficients128_0 = drflac__vrevq_s32(coefficients128_0);
4537 coefficients128_4 = drflac__vrevq_s32(coefficients128_4);
4538 coefficients128_8 = drflac__vrevq_s32(coefficients128_8);
4539 }
4540
4541 /* For this version we are doing one sample at a time. */
4542 while (pDecodedSamples < pDecodedSamplesEnd) {
4543 int32x4_t prediction128;
4544 int32x2_t prediction64;
4545 uint32x4_t zeroCountPart128;
4546 uint32x4_t riceParamPart128;
4547
4548 if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0]) ||
4549 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[1], &riceParamParts[1]) ||
4550 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[2], &riceParamParts[2]) ||
4551 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[3], &riceParamParts[3])) {
4552 return DRFLAC_FALSE;
4553 }
4554
4555 zeroCountPart128 = vld1q_u32(zeroCountParts);
4556 riceParamPart128 = vld1q_u32(riceParamParts);
4557
4558 riceParamPart128 = vandq_u32(riceParamPart128, riceParamMask128);
4559 riceParamPart128 = vorrq_u32(riceParamPart128, vshlq_u32(zeroCountPart128, riceParam128));
4560 riceParamPart128 = veorq_u32(vshrq_n_u32(riceParamPart128, 1), vaddq_u32(drflac__vnotq_u32(vandq_u32(riceParamPart128, one128)), one128));
4561
4562 if (order <= 4) {
4563 for (i = 0; i < 4; i += 1) {
4564 prediction128 = vmulq_s32(coefficients128_0, samples128_0);
4565
4566 /* Horizontal add and shift. */
4567 prediction64 = drflac__vhaddq_s32(prediction128);
4568 prediction64 = vshl_s32(prediction64, shift64);
4569 prediction64 = vadd_s32(prediction64, vget_low_s32(vreinterpretq_s32_u32(riceParamPart128)));
4570
4571 samples128_0 = drflac__valignrq_s32_1(vcombine_s32(prediction64, vdup_n_s32(0)), samples128_0);
4572 riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128);
4573 }
4574 } else if (order <= 8) {
4575 for (i = 0; i < 4; i += 1) {
4576 prediction128 = vmulq_s32(coefficients128_4, samples128_4);
4577 prediction128 = vmlaq_s32(prediction128, coefficients128_0, samples128_0);
4578
4579 /* Horizontal add and shift. */
4580 prediction64 = drflac__vhaddq_s32(prediction128);
4581 prediction64 = vshl_s32(prediction64, shift64);
4582 prediction64 = vadd_s32(prediction64, vget_low_s32(vreinterpretq_s32_u32(riceParamPart128)));
4583
4584 samples128_4 = drflac__valignrq_s32_1(samples128_0, samples128_4);
4585 samples128_0 = drflac__valignrq_s32_1(vcombine_s32(prediction64, vdup_n_s32(0)), samples128_0);
4586 riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128);
4587 }
4588 } else {
4589 for (i = 0; i < 4; i += 1) {
4590 prediction128 = vmulq_s32(coefficients128_8, samples128_8);
4591 prediction128 = vmlaq_s32(prediction128, coefficients128_4, samples128_4);
4592 prediction128 = vmlaq_s32(prediction128, coefficients128_0, samples128_0);
4593
4594 /* Horizontal add and shift. */
4595 prediction64 = drflac__vhaddq_s32(prediction128);
4596 prediction64 = vshl_s32(prediction64, shift64);
4597 prediction64 = vadd_s32(prediction64, vget_low_s32(vreinterpretq_s32_u32(riceParamPart128)));
4598
4599 samples128_8 = drflac__valignrq_s32_1(samples128_4, samples128_8);
4600 samples128_4 = drflac__valignrq_s32_1(samples128_0, samples128_4);
4601 samples128_0 = drflac__valignrq_s32_1(vcombine_s32(prediction64, vdup_n_s32(0)), samples128_0);
4602 riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128);
4603 }
4604 }
4605
4606 /* We store samples in groups of 4. */
4607 vst1q_s32(pDecodedSamples, samples128_0);
4608 pDecodedSamples += 4;
4609 }
4610
4611 /* Make sure we process the last few samples. */
4612 i = (count & ~3);
4613 while (i < (int)count) {
4614 /* Rice extraction. */
4615 if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0])) {
4616 return DRFLAC_FALSE;
4617 }
4618
4619 /* Rice reconstruction. */
4620 riceParamParts[0] &= riceParamMask;
4621 riceParamParts[0] |= (zeroCountParts[0] << riceParam);
4622 riceParamParts[0] = (riceParamParts[0] >> 1) ^ t[riceParamParts[0] & 0x01];
4623
4624 /* Sample reconstruction. */
4625 pDecodedSamples[0] = riceParamParts[0] + drflac__calculate_prediction_32(order, shift, coefficients, pDecodedSamples);
4626
4627 i += 1;
4628 pDecodedSamples += 1;
4629 }
4630
4631 return DRFLAC_TRUE;
4632}
4633
4634static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_64(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
4635{
4636 int i;
4637 drflac_uint32 riceParamMask;
4638 drflac_int32* pDecodedSamples = pSamplesOut;
4639 drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3);
4640 drflac_uint32 zeroCountParts[4];
4641 drflac_uint32 riceParamParts[4];
4642 int32x4_t coefficients128_0;
4643 int32x4_t coefficients128_4;
4644 int32x4_t coefficients128_8;
4645 int32x4_t samples128_0;
4646 int32x4_t samples128_4;
4647 int32x4_t samples128_8;
4648 uint32x4_t riceParamMask128;
4649 int32x4_t riceParam128;
4650 int64x1_t shift64;
4651 uint32x4_t one128;
4652 int64x2_t prediction128 = { 0 };
4653 uint32x4_t zeroCountPart128;
4654 uint32x4_t riceParamPart128;
4655
4656 const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
4657
4658 riceParamMask = (drflac_uint32)~((~0UL) << riceParam);
4659 riceParamMask128 = vdupq_n_u32(riceParamMask);
4660
4661 riceParam128 = vdupq_n_s32(riceParam);
4662 shift64 = vdup_n_s64(-shift); /* Negate the shift because we'll be doing a variable shift using vshlq_s32(). */
4663 one128 = vdupq_n_u32(1);
4664
4665 /*
4666 Pre-loading the coefficients and prior samples is annoying because we need to ensure we don't try reading more than
4667 what's available in the input buffers. It would be convenient to use a fall-through switch to do this, but this results
4668 in strict aliasing warnings with GCC. To work around this I'm just doing something hacky. This feels a bit convoluted
4669 so I think there's opportunity for this to be simplified.
4670 */
4671 {
4672 int runningOrder = order;
4673 drflac_int32 tempC[4] = {0, 0, 0, 0};
4674 drflac_int32 tempS[4] = {0, 0, 0, 0};
4675
4676 /* 0 - 3. */
4677 if (runningOrder >= 4) {
4678 coefficients128_0 = vld1q_s32(coefficients + 0);
4679 samples128_0 = vld1q_s32(pSamplesOut - 4);
4680 runningOrder -= 4;
4681 } else {
4682 switch (runningOrder) {
4683 case 3: tempC[2] = coefficients[2]; tempS[1] = pSamplesOut[-3]; /* fallthrough */
4684 case 2: tempC[1] = coefficients[1]; tempS[2] = pSamplesOut[-2]; /* fallthrough */
4685 case 1: tempC[0] = coefficients[0]; tempS[3] = pSamplesOut[-1]; /* fallthrough */
4686 }
4687
4688 coefficients128_0 = vld1q_s32(tempC);
4689 samples128_0 = vld1q_s32(tempS);
4690 runningOrder = 0;
4691 }
4692
4693 /* 4 - 7 */
4694 if (runningOrder >= 4) {
4695 coefficients128_4 = vld1q_s32(coefficients + 4);
4696 samples128_4 = vld1q_s32(pSamplesOut - 8);
4697 runningOrder -= 4;
4698 } else {
4699 switch (runningOrder) {
4700 case 3: tempC[2] = coefficients[6]; tempS[1] = pSamplesOut[-7]; /* fallthrough */
4701 case 2: tempC[1] = coefficients[5]; tempS[2] = pSamplesOut[-6]; /* fallthrough */
4702 case 1: tempC[0] = coefficients[4]; tempS[3] = pSamplesOut[-5]; /* fallthrough */
4703 }
4704
4705 coefficients128_4 = vld1q_s32(tempC);
4706 samples128_4 = vld1q_s32(tempS);
4707 runningOrder = 0;
4708 }
4709
4710 /* 8 - 11 */
4711 if (runningOrder == 4) {
4712 coefficients128_8 = vld1q_s32(coefficients + 8);
4713 samples128_8 = vld1q_s32(pSamplesOut - 12);
4714 runningOrder -= 4;
4715 } else {
4716 switch (runningOrder) {
4717 case 3: tempC[2] = coefficients[10]; tempS[1] = pSamplesOut[-11]; /* fallthrough */
4718 case 2: tempC[1] = coefficients[ 9]; tempS[2] = pSamplesOut[-10]; /* fallthrough */
4719 case 1: tempC[0] = coefficients[ 8]; tempS[3] = pSamplesOut[- 9]; /* fallthrough */
4720 }
4721
4722 coefficients128_8 = vld1q_s32(tempC);
4723 samples128_8 = vld1q_s32(tempS);
4724 runningOrder = 0;
4725 }
4726
4727 /* Coefficients need to be shuffled for our streaming algorithm below to work. Samples are already in the correct order from the loading routine above. */
4728 coefficients128_0 = drflac__vrevq_s32(coefficients128_0);
4729 coefficients128_4 = drflac__vrevq_s32(coefficients128_4);
4730 coefficients128_8 = drflac__vrevq_s32(coefficients128_8);
4731 }
4732
4733 /* For this version we are doing one sample at a time. */
4734 while (pDecodedSamples < pDecodedSamplesEnd) {
4735 if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0]) ||
4736 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[1], &riceParamParts[1]) ||
4737 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[2], &riceParamParts[2]) ||
4738 !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[3], &riceParamParts[3])) {
4739 return DRFLAC_FALSE;
4740 }
4741
4742 zeroCountPart128 = vld1q_u32(zeroCountParts);
4743 riceParamPart128 = vld1q_u32(riceParamParts);
4744
4745 riceParamPart128 = vandq_u32(riceParamPart128, riceParamMask128);
4746 riceParamPart128 = vorrq_u32(riceParamPart128, vshlq_u32(zeroCountPart128, riceParam128));
4747 riceParamPart128 = veorq_u32(vshrq_n_u32(riceParamPart128, 1), vaddq_u32(drflac__vnotq_u32(vandq_u32(riceParamPart128, one128)), one128));
4748
4749 for (i = 0; i < 4; i += 1) {
4750 int64x1_t prediction64;
4751
4752 prediction128 = veorq_s64(prediction128, prediction128); /* Reset to 0. */
4753 switch (order)
4754 {
4755 case 12:
4756 case 11: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_low_s32(coefficients128_8), vget_low_s32(samples128_8)));
4757 case 10:
4758 case 9: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_high_s32(coefficients128_8), vget_high_s32(samples128_8)));
4759 case 8:
4760 case 7: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_low_s32(coefficients128_4), vget_low_s32(samples128_4)));
4761 case 6:
4762 case 5: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_high_s32(coefficients128_4), vget_high_s32(samples128_4)));
4763 case 4:
4764 case 3: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_low_s32(coefficients128_0), vget_low_s32(samples128_0)));
4765 case 2:
4766 case 1: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_high_s32(coefficients128_0), vget_high_s32(samples128_0)));
4767 }
4768
4769 /* Horizontal add and shift. */
4770 prediction64 = drflac__vhaddq_s64(prediction128);
4771 prediction64 = vshl_s64(prediction64, shift64);
4772 prediction64 = vadd_s64(prediction64, vdup_n_s64(vgetq_lane_u32(riceParamPart128, 0)));
4773
4774 /* Our value should be sitting in prediction64[0]. We need to combine this with our SSE samples. */
4775 samples128_8 = drflac__valignrq_s32_1(samples128_4, samples128_8);
4776 samples128_4 = drflac__valignrq_s32_1(samples128_0, samples128_4);
4777 samples128_0 = drflac__valignrq_s32_1(vcombine_s32(vreinterpret_s32_s64(prediction64), vdup_n_s32(0)), samples128_0);
4778
4779 /* Slide our rice parameter down so that the value in position 0 contains the next one to process. */
4780 riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128);
4781 }
4782
4783 /* We store samples in groups of 4. */
4784 vst1q_s32(pDecodedSamples, samples128_0);
4785 pDecodedSamples += 4;
4786 }
4787
4788 /* Make sure we process the last few samples. */
4789 i = (count & ~3);
4790 while (i < (int)count) {
4791 /* Rice extraction. */
4792 if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0])) {
4793 return DRFLAC_FALSE;
4794 }
4795
4796 /* Rice reconstruction. */
4797 riceParamParts[0] &= riceParamMask;
4798 riceParamParts[0] |= (zeroCountParts[0] << riceParam);
4799 riceParamParts[0] = (riceParamParts[0] >> 1) ^ t[riceParamParts[0] & 0x01];
4800
4801 /* Sample reconstruction. */
4802 pDecodedSamples[0] = riceParamParts[0] + drflac__calculate_prediction_64(order, shift, coefficients, pDecodedSamples);
4803
4804 i += 1;
4805 pDecodedSamples += 1;
4806 }
4807
4808 return DRFLAC_TRUE;
4809}
4810
4811static drflac_bool32 drflac__decode_samples_with_residual__rice__neon(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
4812{
4813 DRFLAC_ASSERT(bs != NULL);
4814 DRFLAC_ASSERT(pSamplesOut != NULL);
4815
4816 /* In my testing the order is rarely > 12, so in this case I'm going to simplify the NEON implementation by only handling order <= 12. */
4817 if (lpcOrder > 0 && lpcOrder <= 12) {
4818 if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) {
4819 return drflac__decode_samples_with_residual__rice__neon_64(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut);
4820 } else {
4821 return drflac__decode_samples_with_residual__rice__neon_32(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut);
4822 }
4823 } else {
4824 return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut);
4825 }
4826}
4827#endif
4828
4829static drflac_bool32 drflac__decode_samples_with_residual__rice(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
4830{
4831#if defined(DRFLAC_SUPPORT_SSE41)
4832 if (drflac__gIsSSE41Supported) {
4833 return drflac__decode_samples_with_residual__rice__sse41(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut);
4834 } else
4835#elif defined(DRFLAC_SUPPORT_NEON)
4836 if (drflac__gIsNEONSupported) {
4837 return drflac__decode_samples_with_residual__rice__neon(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut);
4838 } else
4839#endif
4840 {
4841 /* Scalar fallback. */
4842 #if 0
4843 return drflac__decode_samples_with_residual__rice__reference(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut);
4844 #else
4845 return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut);
4846 #endif
4847 }
4848}
4849
4850/* 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. */
4851static drflac_bool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam)
4852{
4853 drflac_uint32 i;
4854
4855 DRFLAC_ASSERT(bs != NULL);
4856
4857 for (i = 0; i < count; ++i) {
4858 if (!drflac__seek_rice_parts(bs, riceParam)) {
4859 return DRFLAC_FALSE;
4860 }
4861 }
4862
4863 return DRFLAC_TRUE;
4864}
4865
4866#if defined(__clang__)
4867__attribute__((no_sanitize("signed-integer-overflow")))
4868#endif
4869static drflac_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 unencodedBitsPerSample, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
4870{
4871 drflac_uint32 i;
4872
4873 DRFLAC_ASSERT(bs != NULL);
4874 DRFLAC_ASSERT(unencodedBitsPerSample <= 31); /* <-- unencodedBitsPerSample is a 5 bit number, so cannot exceed 31. */
4875 DRFLAC_ASSERT(pSamplesOut != NULL);
4876
4877 for (i = 0; i < count; ++i) {
4878 if (unencodedBitsPerSample > 0) {
4879 if (!drflac__read_int32(bs, unencodedBitsPerSample, pSamplesOut + i)) {
4880 return DRFLAC_FALSE;
4881 }
4882 } else {
4883 pSamplesOut[i] = 0;
4884 }
4885
4886 if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) {
4887 pSamplesOut[i] += drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + i);
4888 } else {
4889 pSamplesOut[i] += drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + i);
4890 }
4891 }
4892
4893 return DRFLAC_TRUE;
4894}
4895
4896
4897/*
4898Reads and decodes the residual for the sub-frame the decoder is currently sitting on. This function should be called
4899when the decoder is sitting at the very start of the RESIDUAL block. The first <order> residuals will be ignored. The
4900<blockSize> and <order> parameters are used to determine how many residual values need to be decoded.
4901*/
4902static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 blockSize, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pDecodedSamples)
4903{
4904 drflac_uint8 residualMethod;
4905 drflac_uint8 partitionOrder;
4906 drflac_uint32 samplesInPartition;
4907 drflac_uint32 partitionsRemaining;
4908
4909 DRFLAC_ASSERT(bs != NULL);
4910 DRFLAC_ASSERT(blockSize != 0);
4911 DRFLAC_ASSERT(pDecodedSamples != NULL); /* <-- Should we allow NULL, in which case we just seek past the residual rather than do a full decode? */
4912
4913 if (!drflac__read_uint8(bs, 2, &residualMethod)) {
4914 return DRFLAC_FALSE;
4915 }
4916
4917 if (residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
4918 return DRFLAC_FALSE; /* Unknown or unsupported residual coding method. */
4919 }
4920
4921 /* Ignore the first <order> values. */
4922 pDecodedSamples += lpcOrder;
4923
4924 if (!drflac__read_uint8(bs, 4, &partitionOrder)) {
4925 return DRFLAC_FALSE;
4926 }
4927
4928 /*
4929 From the FLAC spec:
4930 The Rice partition order in a Rice-coded residual section must be less than or equal to 8.
4931 */
4932 if (partitionOrder > 8) {
4933 return DRFLAC_FALSE;
4934 }
4935
4936 /* Validation check. */
4937 if ((blockSize / (1 << partitionOrder)) < lpcOrder) {
4938 return DRFLAC_FALSE;
4939 }
4940
4941 samplesInPartition = (blockSize / (1 << partitionOrder)) - lpcOrder;
4942 partitionsRemaining = (1 << partitionOrder);
4943 for (;;) {
4944 drflac_uint8 riceParam = 0;
4945 if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) {
4946 if (!drflac__read_uint8(bs, 4, &riceParam)) {
4947 return DRFLAC_FALSE;
4948 }
4949 if (riceParam == 15) {
4950 riceParam = 0xFF;
4951 }
4952 } else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
4953 if (!drflac__read_uint8(bs, 5, &riceParam)) {
4954 return DRFLAC_FALSE;
4955 }
4956 if (riceParam == 31) {
4957 riceParam = 0xFF;
4958 }
4959 }
4960
4961 if (riceParam != 0xFF) {
4962 if (!drflac__decode_samples_with_residual__rice(bs, bitsPerSample, samplesInPartition, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) {
4963 return DRFLAC_FALSE;
4964 }
4965 } else {
4966 drflac_uint8 unencodedBitsPerSample = 0;
4967 if (!drflac__read_uint8(bs, 5, &unencodedBitsPerSample)) {
4968 return DRFLAC_FALSE;
4969 }
4970
4971 if (!drflac__decode_samples_with_residual__unencoded(bs, bitsPerSample, samplesInPartition, unencodedBitsPerSample, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) {
4972 return DRFLAC_FALSE;
4973 }
4974 }
4975
4976 pDecodedSamples += samplesInPartition;
4977
4978 if (partitionsRemaining == 1) {
4979 break;
4980 }
4981
4982 partitionsRemaining -= 1;
4983
4984 if (partitionOrder != 0) {
4985 samplesInPartition = blockSize / (1 << partitionOrder);
4986 }
4987 }
4988
4989 return DRFLAC_TRUE;
4990}
4991
4992/*
4993Reads and seeks past the residual for the sub-frame the decoder is currently sitting on. This function should be called
4994when the decoder is sitting at the very start of the RESIDUAL block. The first <order> residuals will be set to 0. The
4995<blockSize> and <order> parameters are used to determine how many residual values need to be decoded.
4996*/
4997static drflac_bool32 drflac__read_and_seek_residual(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 order)
4998{
4999 drflac_uint8 residualMethod;
5000 drflac_uint8 partitionOrder;
5001 drflac_uint32 samplesInPartition;
5002 drflac_uint32 partitionsRemaining;
5003
5004 DRFLAC_ASSERT(bs != NULL);
5005 DRFLAC_ASSERT(blockSize != 0);
5006
5007 if (!drflac__read_uint8(bs, 2, &residualMethod)) {
5008 return DRFLAC_FALSE;
5009 }
5010
5011 if (residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
5012 return DRFLAC_FALSE; /* Unknown or unsupported residual coding method. */
5013 }
5014
5015 if (!drflac__read_uint8(bs, 4, &partitionOrder)) {
5016 return DRFLAC_FALSE;
5017 }
5018
5019 /*
5020 From the FLAC spec:
5021 The Rice partition order in a Rice-coded residual section must be less than or equal to 8.
5022 */
5023 if (partitionOrder > 8) {
5024 return DRFLAC_FALSE;
5025 }
5026
5027 /* Validation check. */
5028 if ((blockSize / (1 << partitionOrder)) <= order) {
5029 return DRFLAC_FALSE;
5030 }
5031
5032 samplesInPartition = (blockSize / (1 << partitionOrder)) - order;
5033 partitionsRemaining = (1 << partitionOrder);
5034 for (;;)
5035 {
5036 drflac_uint8 riceParam = 0;
5037 if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) {
5038 if (!drflac__read_uint8(bs, 4, &riceParam)) {
5039 return DRFLAC_FALSE;
5040 }
5041 if (riceParam == 15) {
5042 riceParam = 0xFF;
5043 }
5044 } else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
5045 if (!drflac__read_uint8(bs, 5, &riceParam)) {
5046 return DRFLAC_FALSE;
5047 }
5048 if (riceParam == 31) {
5049 riceParam = 0xFF;
5050 }
5051 }
5052
5053 if (riceParam != 0xFF) {
5054 if (!drflac__read_and_seek_residual__rice(bs, samplesInPartition, riceParam)) {
5055 return DRFLAC_FALSE;
5056 }
5057 } else {
5058 drflac_uint8 unencodedBitsPerSample = 0;
5059 if (!drflac__read_uint8(bs, 5, &unencodedBitsPerSample)) {
5060 return DRFLAC_FALSE;
5061 }
5062
5063 if (!drflac__seek_bits(bs, unencodedBitsPerSample * samplesInPartition)) {
5064 return DRFLAC_FALSE;
5065 }
5066 }
5067
5068
5069 if (partitionsRemaining == 1) {
5070 break;
5071 }
5072
5073 partitionsRemaining -= 1;
5074 samplesInPartition = blockSize / (1 << partitionOrder);
5075 }
5076
5077 return DRFLAC_TRUE;
5078}
5079
5080
5081static drflac_bool32 drflac__decode_samples__constant(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_int32* pDecodedSamples)
5082{
5083 drflac_uint32 i;
5084
5085 /* Only a single sample needs to be decoded here. */
5086 drflac_int32 sample;
5087 if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) {
5088 return DRFLAC_FALSE;
5089 }
5090
5091 /*
5092 We don't really need to expand this, but it does simplify the process of reading samples. If this becomes a performance issue (unlikely)
5093 we'll want to look at a more efficient way.
5094 */
5095 for (i = 0; i < blockSize; ++i) {
5096 pDecodedSamples[i] = sample;
5097 }
5098
5099 return DRFLAC_TRUE;
5100}
5101
5102static drflac_bool32 drflac__decode_samples__verbatim(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_int32* pDecodedSamples)
5103{
5104 drflac_uint32 i;
5105
5106 for (i = 0; i < blockSize; ++i) {
5107 drflac_int32 sample;
5108 if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) {
5109 return DRFLAC_FALSE;
5110 }
5111
5112 pDecodedSamples[i] = sample;
5113 }
5114
5115 return DRFLAC_TRUE;
5116}
5117
5118static drflac_bool32 drflac__decode_samples__fixed(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_uint8 lpcOrder, drflac_int32* pDecodedSamples)
5119{
5120 drflac_uint32 i;
5121
5122 static drflac_int32 lpcCoefficientsTable[5][4] = {
5123 {0, 0, 0, 0},
5124 {1, 0, 0, 0},
5125 {2, -1, 0, 0},
5126 {3, -3, 1, 0},
5127 {4, -6, 4, -1}
5128 };
5129
5130 /* Warm up samples and coefficients. */
5131 for (i = 0; i < lpcOrder; ++i) {
5132 drflac_int32 sample;
5133 if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) {
5134 return DRFLAC_FALSE;
5135 }
5136
5137 pDecodedSamples[i] = sample;
5138 }
5139
5140 if (!drflac__decode_samples_with_residual(bs, subframeBitsPerSample, blockSize, lpcOrder, 0, 4, lpcCoefficientsTable[lpcOrder], pDecodedSamples)) {
5141 return DRFLAC_FALSE;
5142 }
5143
5144 return DRFLAC_TRUE;
5145}
5146
5147static drflac_bool32 drflac__decode_samples__lpc(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 bitsPerSample, drflac_uint8 lpcOrder, drflac_int32* pDecodedSamples)
5148{
5149 drflac_uint8 i;
5150 drflac_uint8 lpcPrecision;
5151 drflac_int8 lpcShift;
5152 drflac_int32 coefficients[32];
5153
5154 /* Warm up samples. */
5155 for (i = 0; i < lpcOrder; ++i) {
5156 drflac_int32 sample;
5157 if (!drflac__read_int32(bs, bitsPerSample, &sample)) {
5158 return DRFLAC_FALSE;
5159 }
5160
5161 pDecodedSamples[i] = sample;
5162 }
5163
5164 if (!drflac__read_uint8(bs, 4, &lpcPrecision)) {
5165 return DRFLAC_FALSE;
5166 }
5167 if (lpcPrecision == 15) {
5168 return DRFLAC_FALSE; /* Invalid. */
5169 }
5170 lpcPrecision += 1;
5171
5172 if (!drflac__read_int8(bs, 5, &lpcShift)) {
5173 return DRFLAC_FALSE;
5174 }
5175
5176 /*
5177 From the FLAC specification:
5178
5179 Quantized linear predictor coefficient shift needed in bits (NOTE: this number is signed two's-complement)
5180
5181 Emphasis on the "signed two's-complement". In practice there does not seem to be any encoders nor decoders supporting negative shifts. For now dr_flac is
5182 not going to support negative shifts as I don't have any reference files. However, when a reference file comes through I will consider adding support.
5183 */
5184 if (lpcShift < 0) {
5185 return DRFLAC_FALSE;
5186 }
5187
5188 DRFLAC_ZERO_MEMORY(coefficients, sizeof(coefficients));
5189 for (i = 0; i < lpcOrder; ++i) {
5190 if (!drflac__read_int32(bs, lpcPrecision, coefficients + i)) {
5191 return DRFLAC_FALSE;
5192 }
5193 }
5194
5195 if (!drflac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) {
5196 return DRFLAC_FALSE;
5197 }
5198
5199 return DRFLAC_TRUE;
5200}
5201
5202
5203static drflac_bool32 drflac__read_next_flac_frame_header(drflac_bs* bs, drflac_uint8 streaminfoBitsPerSample, drflac_frame_header* header)
5204{
5205 const drflac_uint32 sampleRateTable[12] = {0, 88200, 176400, 192000, 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000};
5206 const drflac_uint8 bitsPerSampleTable[8] = {0, 8, 12, (drflac_uint8)-1, 16, 20, 24, (drflac_uint8)-1}; /* -1 = reserved. */
5207
5208 DRFLAC_ASSERT(bs != NULL);
5209 DRFLAC_ASSERT(header != NULL);
5210
5211 /* Keep looping until we find a valid sync code. */
5212 for (;;) {
5213 drflac_uint8 crc8 = 0xCE; /* 0xCE = drflac_crc8(0, 0x3FFE, 14); */
5214 drflac_uint8 reserved = 0;
5215 drflac_uint8 blockingStrategy = 0;
5216 drflac_uint8 blockSize = 0;
5217 drflac_uint8 sampleRate = 0;
5218 drflac_uint8 channelAssignment = 0;
5219 drflac_uint8 bitsPerSample = 0;
5220 drflac_bool32 isVariableBlockSize;
5221
5222 if (!drflac__find_and_seek_to_next_sync_code(bs)) {
5223 return DRFLAC_FALSE;
5224 }
5225
5226 if (!drflac__read_uint8(bs, 1, &reserved)) {
5227 return DRFLAC_FALSE;
5228 }
5229 if (reserved == 1) {
5230 continue;
5231 }
5232 crc8 = drflac_crc8(crc8, reserved, 1);
5233
5234 if (!drflac__read_uint8(bs, 1, &blockingStrategy)) {
5235 return DRFLAC_FALSE;
5236 }
5237 crc8 = drflac_crc8(crc8, blockingStrategy, 1);
5238
5239 if (!drflac__read_uint8(bs, 4, &blockSize)) {
5240 return DRFLAC_FALSE;
5241 }
5242 if (blockSize == 0) {
5243 continue;
5244 }
5245 crc8 = drflac_crc8(crc8, blockSize, 4);
5246
5247 if (!drflac__read_uint8(bs, 4, &sampleRate)) {
5248 return DRFLAC_FALSE;
5249 }
5250 crc8 = drflac_crc8(crc8, sampleRate, 4);
5251
5252 if (!drflac__read_uint8(bs, 4, &channelAssignment)) {
5253 return DRFLAC_FALSE;
5254 }
5255 if (channelAssignment > 10) {
5256 continue;
5257 }
5258 crc8 = drflac_crc8(crc8, channelAssignment, 4);
5259
5260 if (!drflac__read_uint8(bs, 3, &bitsPerSample)) {
5261 return DRFLAC_FALSE;
5262 }
5263 if (bitsPerSample == 3 || bitsPerSample == 7) {
5264 continue;
5265 }
5266 crc8 = drflac_crc8(crc8, bitsPerSample, 3);
5267
5268
5269 if (!drflac__read_uint8(bs, 1, &reserved)) {
5270 return DRFLAC_FALSE;
5271 }
5272 if (reserved == 1) {
5273 continue;
5274 }
5275 crc8 = drflac_crc8(crc8, reserved, 1);
5276
5277
5278 isVariableBlockSize = blockingStrategy == 1;
5279 if (isVariableBlockSize) {
5280 drflac_uint64 pcmFrameNumber;
5281 drflac_result result = drflac__read_utf8_coded_number(bs, &pcmFrameNumber, &crc8);
5282 if (result != DRFLAC_SUCCESS) {
5283 if (result == DRFLAC_AT_END) {
5284 return DRFLAC_FALSE;
5285 } else {
5286 continue;
5287 }
5288 }
5289 header->flacFrameNumber = 0;
5290 header->pcmFrameNumber = pcmFrameNumber;
5291 } else {
5292 drflac_uint64 flacFrameNumber = 0;
5293 drflac_result result = drflac__read_utf8_coded_number(bs, &flacFrameNumber, &crc8);
5294 if (result != DRFLAC_SUCCESS) {
5295 if (result == DRFLAC_AT_END) {
5296 return DRFLAC_FALSE;
5297 } else {
5298 continue;
5299 }
5300 }
5301 header->flacFrameNumber = (drflac_uint32)flacFrameNumber; /* <-- Safe cast. */
5302 header->pcmFrameNumber = 0;
5303 }
5304
5305
5306 DRFLAC_ASSERT(blockSize > 0);
5307 if (blockSize == 1) {
5308 header->blockSizeInPCMFrames = 192;
5309 } else if (blockSize <= 5) {
5310 DRFLAC_ASSERT(blockSize >= 2);
5311 header->blockSizeInPCMFrames = 576 * (1 << (blockSize - 2));
5312 } else if (blockSize == 6) {
5313 if (!drflac__read_uint16(bs, 8, &header->blockSizeInPCMFrames)) {
5314 return DRFLAC_FALSE;
5315 }
5316 crc8 = drflac_crc8(crc8, header->blockSizeInPCMFrames, 8);
5317 header->blockSizeInPCMFrames += 1;
5318 } else if (blockSize == 7) {
5319 if (!drflac__read_uint16(bs, 16, &header->blockSizeInPCMFrames)) {
5320 return DRFLAC_FALSE;
5321 }
5322 crc8 = drflac_crc8(crc8, header->blockSizeInPCMFrames, 16);
5323 if (header->blockSizeInPCMFrames == 0xFFFF) {
5324 return DRFLAC_FALSE; /* Frame is too big. This is the size of the frame minus 1. The STREAMINFO block defines the max block size which is 16-bits. Adding one will make it 17 bits and therefore too big. */
5325 }
5326 header->blockSizeInPCMFrames += 1;
5327 } else {
5328 DRFLAC_ASSERT(blockSize >= 8);
5329 header->blockSizeInPCMFrames = 256 * (1 << (blockSize - 8));
5330 }
5331
5332
5333 if (sampleRate <= 11) {
5334 header->sampleRate = sampleRateTable[sampleRate];
5335 } else if (sampleRate == 12) {
5336 if (!drflac__read_uint32(bs, 8, &header->sampleRate)) {
5337 return DRFLAC_FALSE;
5338 }
5339 crc8 = drflac_crc8(crc8, header->sampleRate, 8);
5340 header->sampleRate *= 1000;
5341 } else if (sampleRate == 13) {
5342 if (!drflac__read_uint32(bs, 16, &header->sampleRate)) {
5343 return DRFLAC_FALSE;
5344 }
5345 crc8 = drflac_crc8(crc8, header->sampleRate, 16);
5346 } else if (sampleRate == 14) {
5347 if (!drflac__read_uint32(bs, 16, &header->sampleRate)) {
5348 return DRFLAC_FALSE;
5349 }
5350 crc8 = drflac_crc8(crc8, header->sampleRate, 16);
5351 header->sampleRate *= 10;
5352 } else {
5353 continue; /* Invalid. Assume an invalid block. */
5354 }
5355
5356
5357 header->channelAssignment = channelAssignment;
5358
5359 header->bitsPerSample = bitsPerSampleTable[bitsPerSample];
5360 if (header->bitsPerSample == 0) {
5361 header->bitsPerSample = streaminfoBitsPerSample;
5362 }
5363
5364 if (header->bitsPerSample != streaminfoBitsPerSample) {
5365 /* If this subframe has a different bitsPerSample then streaminfo or the first frame, reject it */
5366 return DRFLAC_FALSE;
5367 }
5368
5369 if (!drflac__read_uint8(bs, 8, &header->crc8)) {
5370 return DRFLAC_FALSE;
5371 }
5372
5373#ifndef DR_FLAC_NO_CRC
5374 if (header->crc8 != crc8) {
5375 continue; /* CRC mismatch. Loop back to the top and find the next sync code. */
5376 }
5377#endif
5378 return DRFLAC_TRUE;
5379 }
5380}
5381
5382static drflac_bool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe* pSubframe)
5383{
5384 drflac_uint8 header;
5385 int type;
5386
5387 if (!drflac__read_uint8(bs, 8, &header)) {
5388 return DRFLAC_FALSE;
5389 }
5390
5391 /* First bit should always be 0. */
5392 if ((header & 0x80) != 0) {
5393 return DRFLAC_FALSE;
5394 }
5395
5396 type = (header & 0x7E) >> 1;
5397 if (type == 0) {
5398 pSubframe->subframeType = DRFLAC_SUBFRAME_CONSTANT;
5399 } else if (type == 1) {
5400 pSubframe->subframeType = DRFLAC_SUBFRAME_VERBATIM;
5401 } else {
5402 if ((type & 0x20) != 0) {
5403 pSubframe->subframeType = DRFLAC_SUBFRAME_LPC;
5404 pSubframe->lpcOrder = (drflac_uint8)(type & 0x1F) + 1;
5405 } else if ((type & 0x08) != 0) {
5406 pSubframe->subframeType = DRFLAC_SUBFRAME_FIXED;
5407 pSubframe->lpcOrder = (drflac_uint8)(type & 0x07);
5408 if (pSubframe->lpcOrder > 4) {
5409 pSubframe->subframeType = DRFLAC_SUBFRAME_RESERVED;
5410 pSubframe->lpcOrder = 0;
5411 }
5412 } else {
5413 pSubframe->subframeType = DRFLAC_SUBFRAME_RESERVED;
5414 }
5415 }
5416
5417 if (pSubframe->subframeType == DRFLAC_SUBFRAME_RESERVED) {
5418 return DRFLAC_FALSE;
5419 }
5420
5421 /* Wasted bits per sample. */
5422 pSubframe->wastedBitsPerSample = 0;
5423 if ((header & 0x01) == 1) {
5424 unsigned int wastedBitsPerSample;
5425 if (!drflac__seek_past_next_set_bit(bs, &wastedBitsPerSample)) {
5426 return DRFLAC_FALSE;
5427 }
5428 pSubframe->wastedBitsPerSample = (drflac_uint8)wastedBitsPerSample + 1;
5429 }
5430
5431 return DRFLAC_TRUE;
5432}
5433
5434static drflac_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex, drflac_int32* pDecodedSamplesOut)
5435{
5436 drflac_subframe* pSubframe;
5437 drflac_uint32 subframeBitsPerSample;
5438
5439 DRFLAC_ASSERT(bs != NULL);
5440 DRFLAC_ASSERT(frame != NULL);
5441
5442 pSubframe = frame->subframes + subframeIndex;
5443 if (!drflac__read_subframe_header(bs, pSubframe)) {
5444 return DRFLAC_FALSE;
5445 }
5446
5447 /* Side channels require an extra bit per sample. Took a while to figure that one out... */
5448 subframeBitsPerSample = frame->header.bitsPerSample;
5449 if ((frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) {
5450 subframeBitsPerSample += 1;
5451 } else if (frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) {
5452 subframeBitsPerSample += 1;
5453 }
5454
5455 if (subframeBitsPerSample > 32) {
5456 /* libFLAC and ffmpeg reject 33-bit subframes as well */
5457 return DRFLAC_FALSE;
5458 }
5459
5460 /* Need to handle wasted bits per sample. */
5461 if (pSubframe->wastedBitsPerSample >= subframeBitsPerSample) {
5462 return DRFLAC_FALSE;
5463 }
5464 subframeBitsPerSample -= pSubframe->wastedBitsPerSample;
5465
5466 pSubframe->pSamplesS32 = pDecodedSamplesOut;
5467
5468 switch (pSubframe->subframeType)
5469 {
5470 case DRFLAC_SUBFRAME_CONSTANT:
5471 {
5472 drflac__decode_samples__constant(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->pSamplesS32);
5473 } break;
5474
5475 case DRFLAC_SUBFRAME_VERBATIM:
5476 {
5477 drflac__decode_samples__verbatim(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->pSamplesS32);
5478 } break;
5479
5480 case DRFLAC_SUBFRAME_FIXED:
5481 {
5482 drflac__decode_samples__fixed(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->lpcOrder, pSubframe->pSamplesS32);
5483 } break;
5484
5485 case DRFLAC_SUBFRAME_LPC:
5486 {
5487 drflac__decode_samples__lpc(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->lpcOrder, pSubframe->pSamplesS32);
5488 } break;
5489
5490 default: return DRFLAC_FALSE;
5491 }
5492
5493 return DRFLAC_TRUE;
5494}
5495
5496static drflac_bool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex)
5497{
5498 drflac_subframe* pSubframe;
5499 drflac_uint32 subframeBitsPerSample;
5500
5501 DRFLAC_ASSERT(bs != NULL);
5502 DRFLAC_ASSERT(frame != NULL);
5503
5504 pSubframe = frame->subframes + subframeIndex;
5505 if (!drflac__read_subframe_header(bs, pSubframe)) {
5506 return DRFLAC_FALSE;
5507 }
5508
5509 /* Side channels require an extra bit per sample. Took a while to figure that one out... */
5510 subframeBitsPerSample = frame->header.bitsPerSample;
5511 if ((frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) {
5512 subframeBitsPerSample += 1;
5513 } else if (frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) {
5514 subframeBitsPerSample += 1;
5515 }
5516
5517 /* Need to handle wasted bits per sample. */
5518 if (pSubframe->wastedBitsPerSample >= subframeBitsPerSample) {
5519 return DRFLAC_FALSE;
5520 }
5521 subframeBitsPerSample -= pSubframe->wastedBitsPerSample;
5522
5523 pSubframe->pSamplesS32 = NULL;
5524
5525 switch (pSubframe->subframeType)
5526 {
5527 case DRFLAC_SUBFRAME_CONSTANT:
5528 {
5529 if (!drflac__seek_bits(bs, subframeBitsPerSample)) {
5530 return DRFLAC_FALSE;
5531 }
5532 } break;
5533
5534 case DRFLAC_SUBFRAME_VERBATIM:
5535 {
5536 unsigned int bitsToSeek = frame->header.blockSizeInPCMFrames * subframeBitsPerSample;
5537 if (!drflac__seek_bits(bs, bitsToSeek)) {
5538 return DRFLAC_FALSE;
5539 }
5540 } break;
5541
5542 case DRFLAC_SUBFRAME_FIXED:
5543 {
5544 unsigned int bitsToSeek = pSubframe->lpcOrder * subframeBitsPerSample;
5545 if (!drflac__seek_bits(bs, bitsToSeek)) {
5546 return DRFLAC_FALSE;
5547 }
5548
5549 if (!drflac__read_and_seek_residual(bs, frame->header.blockSizeInPCMFrames, pSubframe->lpcOrder)) {
5550 return DRFLAC_FALSE;
5551 }
5552 } break;
5553
5554 case DRFLAC_SUBFRAME_LPC:
5555 {
5556 drflac_uint8 lpcPrecision;
5557
5558 unsigned int bitsToSeek = pSubframe->lpcOrder * subframeBitsPerSample;
5559 if (!drflac__seek_bits(bs, bitsToSeek)) {
5560 return DRFLAC_FALSE;
5561 }
5562
5563 if (!drflac__read_uint8(bs, 4, &lpcPrecision)) {
5564 return DRFLAC_FALSE;
5565 }
5566 if (lpcPrecision == 15) {
5567 return DRFLAC_FALSE; /* Invalid. */
5568 }
5569 lpcPrecision += 1;
5570
5571
5572 bitsToSeek = (pSubframe->lpcOrder * lpcPrecision) + 5; /* +5 for shift. */
5573 if (!drflac__seek_bits(bs, bitsToSeek)) {
5574 return DRFLAC_FALSE;
5575 }
5576
5577 if (!drflac__read_and_seek_residual(bs, frame->header.blockSizeInPCMFrames, pSubframe->lpcOrder)) {
5578 return DRFLAC_FALSE;
5579 }
5580 } break;
5581
5582 default: return DRFLAC_FALSE;
5583 }
5584
5585 return DRFLAC_TRUE;
5586}
5587
5588
5589static DRFLAC_INLINE drflac_uint8 drflac__get_channel_count_from_channel_assignment(drflac_int8 channelAssignment)
5590{
5591 drflac_uint8 lookup[] = {1, 2, 3, 4, 5, 6, 7, 8, 2, 2, 2};
5592
5593 DRFLAC_ASSERT(channelAssignment <= 10);
5594 return lookup[channelAssignment];
5595}
5596
5597static drflac_result drflac__decode_flac_frame(drflac* pFlac)
5598{
5599 int channelCount;
5600 int i;
5601 drflac_uint8 paddingSizeInBits;
5602 drflac_uint16 desiredCRC16;
5603#ifndef DR_FLAC_NO_CRC
5604 drflac_uint16 actualCRC16;
5605#endif
5606
5607 /* This function should be called while the stream is sitting on the first byte after the frame header. */
5608 DRFLAC_ZERO_MEMORY(pFlac->currentFLACFrame.subframes, sizeof(pFlac->currentFLACFrame.subframes));
5609
5610 /* The frame block size must never be larger than the maximum block size defined by the FLAC stream. */
5611 if (pFlac->currentFLACFrame.header.blockSizeInPCMFrames > pFlac->maxBlockSizeInPCMFrames) {
5612 return DRFLAC_ERROR;
5613 }
5614
5615 /* The number of channels in the frame must match the channel count from the STREAMINFO block. */
5616 channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment);
5617 if (channelCount != (int)pFlac->channels) {
5618 return DRFLAC_ERROR;
5619 }
5620
5621 for (i = 0; i < channelCount; ++i) {
5622 if (!drflac__decode_subframe(&pFlac->bs, &pFlac->currentFLACFrame, i, pFlac->pDecodedSamples + (pFlac->currentFLACFrame.header.blockSizeInPCMFrames * i))) {
5623 return DRFLAC_ERROR;
5624 }
5625 }
5626
5627 paddingSizeInBits = (drflac_uint8)(DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7);
5628 if (paddingSizeInBits > 0) {
5629 drflac_uint8 padding = 0;
5630 if (!drflac__read_uint8(&pFlac->bs, paddingSizeInBits, &padding)) {
5631 return DRFLAC_AT_END;
5632 }
5633 }
5634
5635#ifndef DR_FLAC_NO_CRC
5636 actualCRC16 = drflac__flush_crc16(&pFlac->bs);
5637#endif
5638 if (!drflac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) {
5639 return DRFLAC_AT_END;
5640 }
5641
5642#ifndef DR_FLAC_NO_CRC
5643 if (actualCRC16 != desiredCRC16) {
5644 return DRFLAC_CRC_MISMATCH; /* CRC mismatch. */
5645 }
5646#endif
5647
5648 pFlac->currentFLACFrame.pcmFramesRemaining = pFlac->currentFLACFrame.header.blockSizeInPCMFrames;
5649
5650 return DRFLAC_SUCCESS;
5651}
5652
5653static drflac_result drflac__seek_flac_frame(drflac* pFlac)
5654{
5655 int channelCount;
5656 int i;
5657 drflac_uint16 desiredCRC16;
5658#ifndef DR_FLAC_NO_CRC
5659 drflac_uint16 actualCRC16;
5660#endif
5661
5662 channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment);
5663 for (i = 0; i < channelCount; ++i) {
5664 if (!drflac__seek_subframe(&pFlac->bs, &pFlac->currentFLACFrame, i)) {
5665 return DRFLAC_ERROR;
5666 }
5667 }
5668
5669 /* Padding. */
5670 if (!drflac__seek_bits(&pFlac->bs, DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7)) {
5671 return DRFLAC_ERROR;
5672 }
5673
5674 /* CRC. */
5675#ifndef DR_FLAC_NO_CRC
5676 actualCRC16 = drflac__flush_crc16(&pFlac->bs);
5677#endif
5678 if (!drflac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) {
5679 return DRFLAC_AT_END;
5680 }
5681
5682#ifndef DR_FLAC_NO_CRC
5683 if (actualCRC16 != desiredCRC16) {
5684 return DRFLAC_CRC_MISMATCH; /* CRC mismatch. */
5685 }
5686#endif
5687
5688 return DRFLAC_SUCCESS;
5689}
5690
5691static drflac_bool32 drflac__read_and_decode_next_flac_frame(drflac* pFlac)
5692{
5693 DRFLAC_ASSERT(pFlac != NULL);
5694
5695 for (;;) {
5696 drflac_result result;
5697
5698 if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
5699 return DRFLAC_FALSE;
5700 }
5701
5702 result = drflac__decode_flac_frame(pFlac);
5703 if (result != DRFLAC_SUCCESS) {
5704 if (result == DRFLAC_CRC_MISMATCH) {
5705 continue; /* CRC mismatch. Skip to the next frame. */
5706 } else {
5707 return DRFLAC_FALSE;
5708 }
5709 }
5710
5711 return DRFLAC_TRUE;
5712 }
5713}
5714
5715static void drflac__get_pcm_frame_range_of_current_flac_frame(drflac* pFlac, drflac_uint64* pFirstPCMFrame, drflac_uint64* pLastPCMFrame)
5716{
5717 drflac_uint64 firstPCMFrame;
5718 drflac_uint64 lastPCMFrame;
5719
5720 DRFLAC_ASSERT(pFlac != NULL);
5721
5722 firstPCMFrame = pFlac->currentFLACFrame.header.pcmFrameNumber;
5723 if (firstPCMFrame == 0) {
5724 firstPCMFrame = ((drflac_uint64)pFlac->currentFLACFrame.header.flacFrameNumber) * pFlac->maxBlockSizeInPCMFrames;
5725 }
5726
5727 lastPCMFrame = firstPCMFrame + pFlac->currentFLACFrame.header.blockSizeInPCMFrames;
5728 if (lastPCMFrame > 0) {
5729 lastPCMFrame -= 1; /* Needs to be zero based. */
5730 }
5731
5732 if (pFirstPCMFrame) {
5733 *pFirstPCMFrame = firstPCMFrame;
5734 }
5735 if (pLastPCMFrame) {
5736 *pLastPCMFrame = lastPCMFrame;
5737 }
5738}
5739
5740static drflac_bool32 drflac__seek_to_first_frame(drflac* pFlac)
5741{
5742 drflac_bool32 result;
5743
5744 DRFLAC_ASSERT(pFlac != NULL);
5745
5746 result = drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes);
5747
5748 DRFLAC_ZERO_MEMORY(&pFlac->currentFLACFrame, sizeof(pFlac->currentFLACFrame));
5749 pFlac->currentPCMFrame = 0;
5750
5751 return result;
5752}
5753
5754static DRFLAC_INLINE drflac_result drflac__seek_to_next_flac_frame(drflac* pFlac)
5755{
5756 /* This function should only ever be called while the decoder is sitting on the first byte past the FRAME_HEADER section. */
5757 DRFLAC_ASSERT(pFlac != NULL);
5758 return drflac__seek_flac_frame(pFlac);
5759}
5760
5761
5762static drflac_uint64 drflac__seek_forward_by_pcm_frames(drflac* pFlac, drflac_uint64 pcmFramesToSeek)
5763{
5764 drflac_uint64 pcmFramesRead = 0;
5765 while (pcmFramesToSeek > 0) {
5766 if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
5767 if (!drflac__read_and_decode_next_flac_frame(pFlac)) {
5768 break; /* Couldn't read the next frame, so just break from the loop and return. */
5769 }
5770 } else {
5771 if (pFlac->currentFLACFrame.pcmFramesRemaining > pcmFramesToSeek) {
5772 pcmFramesRead += pcmFramesToSeek;
5773 pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)pcmFramesToSeek; /* <-- Safe cast. Will always be < currentFrame.pcmFramesRemaining < 65536. */
5774 pcmFramesToSeek = 0;
5775 } else {
5776 pcmFramesRead += pFlac->currentFLACFrame.pcmFramesRemaining;
5777 pcmFramesToSeek -= pFlac->currentFLACFrame.pcmFramesRemaining;
5778 pFlac->currentFLACFrame.pcmFramesRemaining = 0;
5779 }
5780 }
5781 }
5782
5783 pFlac->currentPCMFrame += pcmFramesRead;
5784 return pcmFramesRead;
5785}
5786
5787
5788static drflac_bool32 drflac__seek_to_pcm_frame__brute_force(drflac* pFlac, drflac_uint64 pcmFrameIndex)
5789{
5790 drflac_bool32 isMidFrame = DRFLAC_FALSE;
5791 drflac_uint64 runningPCMFrameCount;
5792
5793 DRFLAC_ASSERT(pFlac != NULL);
5794
5795 /* If we are seeking forward we start from the current position. Otherwise we need to start all the way from the start of the file. */
5796 if (pcmFrameIndex >= pFlac->currentPCMFrame) {
5797 /* Seeking forward. Need to seek from the current position. */
5798 runningPCMFrameCount = pFlac->currentPCMFrame;
5799
5800 /* The frame header for the first frame may not yet have been read. We need to do that if necessary. */
5801 if (pFlac->currentPCMFrame == 0 && pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
5802 if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
5803 return DRFLAC_FALSE;
5804 }
5805 } else {
5806 isMidFrame = DRFLAC_TRUE;
5807 }
5808 } else {
5809 /* Seeking backwards. Need to seek from the start of the file. */
5810 runningPCMFrameCount = 0;
5811
5812 /* Move back to the start. */
5813 if (!drflac__seek_to_first_frame(pFlac)) {
5814 return DRFLAC_FALSE;
5815 }
5816
5817 /* Decode the first frame in preparation for sample-exact seeking below. */
5818 if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
5819 return DRFLAC_FALSE;
5820 }
5821 }
5822
5823 /*
5824 We need to as quickly as possible find the frame that contains the target sample. To do this, we iterate over each frame and inspect its
5825 header. If based on the header we can determine that the frame contains the sample, we do a full decode of that frame.
5826 */
5827 for (;;) {
5828 drflac_uint64 pcmFrameCountInThisFLACFrame;
5829 drflac_uint64 firstPCMFrameInFLACFrame = 0;
5830 drflac_uint64 lastPCMFrameInFLACFrame = 0;
5831
5832 drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame);
5833
5834 pcmFrameCountInThisFLACFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1;
5835 if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFLACFrame)) {
5836 /*
5837 The sample should be in this frame. We need to fully decode it, however if it's an invalid frame (a CRC mismatch), we need to pretend
5838 it never existed and keep iterating.
5839 */
5840 drflac_uint64 pcmFramesToDecode = pcmFrameIndex - runningPCMFrameCount;
5841
5842 if (!isMidFrame) {
5843 drflac_result result = drflac__decode_flac_frame(pFlac);
5844 if (result == DRFLAC_SUCCESS) {
5845 /* The frame is valid. We just need to skip over some samples to ensure it's sample-exact. */
5846 return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; /* <-- If this fails, something bad has happened (it should never fail). */
5847 } else {
5848 if (result == DRFLAC_CRC_MISMATCH) {
5849 goto next_iteration; /* CRC mismatch. Pretend this frame never existed. */
5850 } else {
5851 return DRFLAC_FALSE;
5852 }
5853 }
5854 } else {
5855 /* We started seeking mid-frame which means we need to skip the frame decoding part. */
5856 return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode;
5857 }
5858 } else {
5859 /*
5860 It's not in this frame. We need to seek past the frame, but check if there was a CRC mismatch. If so, we pretend this
5861 frame never existed and leave the running sample count untouched.
5862 */
5863 if (!isMidFrame) {
5864 drflac_result result = drflac__seek_to_next_flac_frame(pFlac);
5865 if (result == DRFLAC_SUCCESS) {
5866 runningPCMFrameCount += pcmFrameCountInThisFLACFrame;
5867 } else {
5868 if (result == DRFLAC_CRC_MISMATCH) {
5869 goto next_iteration; /* CRC mismatch. Pretend this frame never existed. */
5870 } else {
5871 return DRFLAC_FALSE;
5872 }
5873 }
5874 } else {
5875 /*
5876 We started seeking mid-frame which means we need to seek by reading to the end of the frame instead of with
5877 drflac__seek_to_next_flac_frame() which only works if the decoder is sitting on the byte just after the frame header.
5878 */
5879 runningPCMFrameCount += pFlac->currentFLACFrame.pcmFramesRemaining;
5880 pFlac->currentFLACFrame.pcmFramesRemaining = 0;
5881 isMidFrame = DRFLAC_FALSE;
5882 }
5883
5884 /* If we are seeking to the end of the file and we've just hit it, we're done. */
5885 if (pcmFrameIndex == pFlac->totalPCMFrameCount && runningPCMFrameCount == pFlac->totalPCMFrameCount) {
5886 return DRFLAC_TRUE;
5887 }
5888 }
5889
5890 next_iteration:
5891 /* Grab the next frame in preparation for the next iteration. */
5892 if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
5893 return DRFLAC_FALSE;
5894 }
5895 }
5896}
5897
5898
5899#if !defined(DR_FLAC_NO_CRC)
5900/*
5901We use an average compression ratio to determine our approximate start location. FLAC files are generally about 50%-70% the size of their
5902uncompressed counterparts so we'll use this as a basis. I'm going to split the middle and use a factor of 0.6 to determine the starting
5903location.
5904*/
5905#define DRFLAC_BINARY_SEARCH_APPROX_COMPRESSION_RATIO 0.6f
5906
5907static drflac_bool32 drflac__seek_to_approximate_flac_frame_to_byte(drflac* pFlac, drflac_uint64 targetByte, drflac_uint64 rangeLo, drflac_uint64 rangeHi, drflac_uint64* pLastSuccessfulSeekOffset)
5908{
5909 DRFLAC_ASSERT(pFlac != NULL);
5910 DRFLAC_ASSERT(pLastSuccessfulSeekOffset != NULL);
5911 DRFLAC_ASSERT(targetByte >= rangeLo);
5912 DRFLAC_ASSERT(targetByte <= rangeHi);
5913
5914 *pLastSuccessfulSeekOffset = pFlac->firstFLACFramePosInBytes;
5915
5916 for (;;) {
5917 /* After rangeLo == rangeHi == targetByte fails, we need to break out. */
5918 drflac_uint64 lastTargetByte = targetByte;
5919
5920 /* When seeking to a byte, failure probably means we've attempted to seek beyond the end of the stream. To counter this we just halve it each attempt. */
5921 if (!drflac__seek_to_byte(&pFlac->bs, targetByte)) {
5922 /* If we couldn't even seek to the first byte in the stream we have a problem. Just abandon the whole thing. */
5923 if (targetByte == 0) {
5924 drflac__seek_to_first_frame(pFlac); /* Try to recover. */
5925 return DRFLAC_FALSE;
5926 }
5927
5928 /* Halve the byte location and continue. */
5929 targetByte = rangeLo + ((rangeHi - rangeLo)/2);
5930 rangeHi = targetByte;
5931 } else {
5932 /* Getting here should mean that we have seeked to an appropriate byte. */
5933
5934 /* Clear the details of the FLAC frame so we don't misreport data. */
5935 DRFLAC_ZERO_MEMORY(&pFlac->currentFLACFrame, sizeof(pFlac->currentFLACFrame));
5936
5937 /*
5938 Now seek to the next FLAC frame. We need to decode the entire frame (not just the header) because it's possible for the header to incorrectly pass the
5939 CRC check and return bad data. We need to decode the entire frame to be more certain. Although this seems unlikely, this has happened to me in testing
5940 so it needs to stay this way for now.
5941 */
5942#if 1
5943 if (!drflac__read_and_decode_next_flac_frame(pFlac)) {
5944 /* Halve the byte location and continue. */
5945 targetByte = rangeLo + ((rangeHi - rangeLo)/2);
5946 rangeHi = targetByte;
5947 } else {
5948 break;
5949 }
5950#else
5951 if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
5952 /* Halve the byte location and continue. */
5953 targetByte = rangeLo + ((rangeHi - rangeLo)/2);
5954 rangeHi = targetByte;
5955 } else {
5956 break;
5957 }
5958#endif
5959 }
5960
5961 /* We already tried this byte and there are no more to try, break out. */
5962 if(targetByte == lastTargetByte) {
5963 return DRFLAC_FALSE;
5964 }
5965 }
5966
5967 /* The current PCM frame needs to be updated based on the frame we just seeked to. */
5968 drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &pFlac->currentPCMFrame, NULL);
5969
5970 DRFLAC_ASSERT(targetByte <= rangeHi);
5971
5972 *pLastSuccessfulSeekOffset = targetByte;
5973 return DRFLAC_TRUE;
5974}
5975
5976static drflac_bool32 drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(drflac* pFlac, drflac_uint64 offset)
5977{
5978 /* This section of code would be used if we were only decoding the FLAC frame header when calling drflac__seek_to_approximate_flac_frame_to_byte(). */
5979#if 0
5980 if (drflac__decode_flac_frame(pFlac) != DRFLAC_SUCCESS) {
5981 /* We failed to decode this frame which may be due to it being corrupt. We'll just use the next valid FLAC frame. */
5982 if (drflac__read_and_decode_next_flac_frame(pFlac) == DRFLAC_FALSE) {
5983 return DRFLAC_FALSE;
5984 }
5985 }
5986#endif
5987
5988 return drflac__seek_forward_by_pcm_frames(pFlac, offset) == offset;
5989}
5990
5991
5992static drflac_bool32 drflac__seek_to_pcm_frame__binary_search_internal(drflac* pFlac, drflac_uint64 pcmFrameIndex, drflac_uint64 byteRangeLo, drflac_uint64 byteRangeHi)
5993{
5994 /* This assumes pFlac->currentPCMFrame is sitting on byteRangeLo upon entry. */
5995
5996 drflac_uint64 targetByte;
5997 drflac_uint64 pcmRangeLo = pFlac->totalPCMFrameCount;
5998 drflac_uint64 pcmRangeHi = 0;
5999 drflac_uint64 lastSuccessfulSeekOffset = (drflac_uint64)-1;
6000 drflac_uint64 closestSeekOffsetBeforeTargetPCMFrame = byteRangeLo;
6001 drflac_uint32 seekForwardThreshold = (pFlac->maxBlockSizeInPCMFrames != 0) ? pFlac->maxBlockSizeInPCMFrames*2 : 4096;
6002
6003 targetByte = byteRangeLo + (drflac_uint64)(((drflac_int64)((pcmFrameIndex - pFlac->currentPCMFrame) * pFlac->channels * pFlac->bitsPerSample)/8.0f) * DRFLAC_BINARY_SEARCH_APPROX_COMPRESSION_RATIO);
6004 if (targetByte > byteRangeHi) {
6005 targetByte = byteRangeHi;
6006 }
6007
6008 for (;;) {
6009 if (drflac__seek_to_approximate_flac_frame_to_byte(pFlac, targetByte, byteRangeLo, byteRangeHi, &lastSuccessfulSeekOffset)) {
6010 /* We found a FLAC frame. We need to check if it contains the sample we're looking for. */
6011 drflac_uint64 newPCMRangeLo;
6012 drflac_uint64 newPCMRangeHi;
6013 drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &newPCMRangeLo, &newPCMRangeHi);
6014
6015 /* If we selected the same frame, it means we should be pretty close. Just decode the rest. */
6016 if (pcmRangeLo == newPCMRangeLo) {
6017 if (!drflac__seek_to_approximate_flac_frame_to_byte(pFlac, closestSeekOffsetBeforeTargetPCMFrame, closestSeekOffsetBeforeTargetPCMFrame, byteRangeHi, &lastSuccessfulSeekOffset)) {
6018 break; /* Failed to seek to closest frame. */
6019 }
6020
6021 if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame)) {
6022 return DRFLAC_TRUE;
6023 } else {
6024 break; /* Failed to seek forward. */
6025 }
6026 }
6027
6028 pcmRangeLo = newPCMRangeLo;
6029 pcmRangeHi = newPCMRangeHi;
6030
6031 if (pcmRangeLo <= pcmFrameIndex && pcmRangeHi >= pcmFrameIndex) {
6032 /* The target PCM frame is in this FLAC frame. */
6033 if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame) ) {
6034 return DRFLAC_TRUE;
6035 } else {
6036 break; /* Failed to seek to FLAC frame. */
6037 }
6038 } else {
6039 const float approxCompressionRatio = (drflac_int64)(lastSuccessfulSeekOffset - pFlac->firstFLACFramePosInBytes) / ((drflac_int64)(pcmRangeLo * pFlac->channels * pFlac->bitsPerSample)/8.0f);
6040
6041 if (pcmRangeLo > pcmFrameIndex) {
6042 /* We seeked too far forward. We need to move our target byte backward and try again. */
6043 byteRangeHi = lastSuccessfulSeekOffset;
6044 if (byteRangeLo > byteRangeHi) {
6045 byteRangeLo = byteRangeHi;
6046 }
6047
6048 targetByte = byteRangeLo + ((byteRangeHi - byteRangeLo) / 2);
6049 if (targetByte < byteRangeLo) {
6050 targetByte = byteRangeLo;
6051 }
6052 } else /*if (pcmRangeHi < pcmFrameIndex)*/ {
6053 /* We didn't seek far enough. We need to move our target byte forward and try again. */
6054
6055 /* If we're close enough we can just seek forward. */
6056 if ((pcmFrameIndex - pcmRangeLo) < seekForwardThreshold) {
6057 if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame)) {
6058 return DRFLAC_TRUE;
6059 } else {
6060 break; /* Failed to seek to FLAC frame. */
6061 }
6062 } else {
6063 byteRangeLo = lastSuccessfulSeekOffset;
6064 if (byteRangeHi < byteRangeLo) {
6065 byteRangeHi = byteRangeLo;
6066 }
6067
6068 targetByte = lastSuccessfulSeekOffset + (drflac_uint64)(((drflac_int64)((pcmFrameIndex-pcmRangeLo) * pFlac->channels * pFlac->bitsPerSample)/8.0f) * approxCompressionRatio);
6069 if (targetByte > byteRangeHi) {
6070 targetByte = byteRangeHi;
6071 }
6072
6073 if (closestSeekOffsetBeforeTargetPCMFrame < lastSuccessfulSeekOffset) {
6074 closestSeekOffsetBeforeTargetPCMFrame = lastSuccessfulSeekOffset;
6075 }
6076 }
6077 }
6078 }
6079 } else {
6080 /* Getting here is really bad. We just recover as best we can, but moving to the first frame in the stream, and then abort. */
6081 break;
6082 }
6083 }
6084
6085 drflac__seek_to_first_frame(pFlac); /* <-- Try to recover. */
6086 return DRFLAC_FALSE;
6087}
6088
6089static drflac_bool32 drflac__seek_to_pcm_frame__binary_search(drflac* pFlac, drflac_uint64 pcmFrameIndex)
6090{
6091 drflac_uint64 byteRangeLo;
6092 drflac_uint64 byteRangeHi;
6093 drflac_uint32 seekForwardThreshold = (pFlac->maxBlockSizeInPCMFrames != 0) ? pFlac->maxBlockSizeInPCMFrames*2 : 4096;
6094
6095 /* Our algorithm currently assumes the FLAC stream is currently sitting at the start. */
6096 if (drflac__seek_to_first_frame(pFlac) == DRFLAC_FALSE) {
6097 return DRFLAC_FALSE;
6098 }
6099
6100 /* If we're close enough to the start, just move to the start and seek forward. */
6101 if (pcmFrameIndex < seekForwardThreshold) {
6102 return drflac__seek_forward_by_pcm_frames(pFlac, pcmFrameIndex) == pcmFrameIndex;
6103 }
6104
6105 /*
6106 Our starting byte range is the byte position of the first FLAC frame and the approximate end of the file as if it were completely uncompressed. This ensures
6107 the entire file is included, even though most of the time it'll exceed the end of the actual stream. This is OK as the frame searching logic will handle it.
6108 */
6109 byteRangeLo = pFlac->firstFLACFramePosInBytes;
6110 byteRangeHi = pFlac->firstFLACFramePosInBytes + (drflac_uint64)((drflac_int64)(pFlac->totalPCMFrameCount * pFlac->channels * pFlac->bitsPerSample)/8.0f);
6111
6112 return drflac__seek_to_pcm_frame__binary_search_internal(pFlac, pcmFrameIndex, byteRangeLo, byteRangeHi);
6113}
6114#endif /* !DR_FLAC_NO_CRC */
6115
6116static drflac_bool32 drflac__seek_to_pcm_frame__seek_table(drflac* pFlac, drflac_uint64 pcmFrameIndex)
6117{
6118 drflac_uint32 iClosestSeekpoint = 0;
6119 drflac_bool32 isMidFrame = DRFLAC_FALSE;
6120 drflac_uint64 runningPCMFrameCount;
6121 drflac_uint32 iSeekpoint;
6122
6123
6124 DRFLAC_ASSERT(pFlac != NULL);
6125
6126 if (pFlac->pSeekpoints == NULL || pFlac->seekpointCount == 0) {
6127 return DRFLAC_FALSE;
6128 }
6129
6130 /* Do not use the seektable if pcmFramIndex is not coverd by it. */
6131 if (pFlac->pSeekpoints[0].firstPCMFrame > pcmFrameIndex) {
6132 return DRFLAC_FALSE;
6133 }
6134
6135 for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) {
6136 if (pFlac->pSeekpoints[iSeekpoint].firstPCMFrame >= pcmFrameIndex) {
6137 break;
6138 }
6139
6140 iClosestSeekpoint = iSeekpoint;
6141 }
6142
6143 /* There's been cases where the seek table contains only zeros. We need to do some basic validation on the closest seekpoint. */
6144 if (pFlac->pSeekpoints[iClosestSeekpoint].pcmFrameCount == 0 || pFlac->pSeekpoints[iClosestSeekpoint].pcmFrameCount > pFlac->maxBlockSizeInPCMFrames) {
6145 return DRFLAC_FALSE;
6146 }
6147 if (pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame > pFlac->totalPCMFrameCount && pFlac->totalPCMFrameCount > 0) {
6148 return DRFLAC_FALSE;
6149 }
6150
6151#if !defined(DR_FLAC_NO_CRC)
6152 /* At this point we should know the closest seek point. We can use a binary search for this. We need to know the total sample count for this. */
6153 if (pFlac->totalPCMFrameCount > 0) {
6154 drflac_uint64 byteRangeLo;
6155 drflac_uint64 byteRangeHi;
6156
6157 byteRangeHi = pFlac->firstFLACFramePosInBytes + (drflac_uint64)((drflac_int64)(pFlac->totalPCMFrameCount * pFlac->channels * pFlac->bitsPerSample)/8.0f);
6158 byteRangeLo = pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset;
6159
6160 /*
6161 If our closest seek point is not the last one, we only need to search between it and the next one. The section below calculates an appropriate starting
6162 value for byteRangeHi which will clamp it appropriately.
6163
6164 Note that the next seekpoint must have an offset greater than the closest seekpoint because otherwise our binary search algorithm will break down. There
6165 have been cases where a seektable consists of seek points where every byte offset is set to 0 which causes problems. If this happens we need to abort.
6166 */
6167 if (iClosestSeekpoint < pFlac->seekpointCount-1) {
6168 drflac_uint32 iNextSeekpoint = iClosestSeekpoint + 1;
6169
6170 /* Basic validation on the seekpoints to ensure they're usable. */
6171 if (pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset >= pFlac->pSeekpoints[iNextSeekpoint].flacFrameOffset || pFlac->pSeekpoints[iNextSeekpoint].pcmFrameCount == 0) {
6172 return DRFLAC_FALSE; /* The next seekpoint doesn't look right. The seek table cannot be trusted from here. Abort. */
6173 }
6174
6175 if (pFlac->pSeekpoints[iNextSeekpoint].firstPCMFrame != (((drflac_uint64)0xFFFFFFFF << 32) | 0xFFFFFFFF)) { /* Make sure it's not a placeholder seekpoint. */
6176 byteRangeHi = pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iNextSeekpoint].flacFrameOffset - 1; /* byteRangeHi must be zero based. */
6177 }
6178 }
6179
6180 if (drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset)) {
6181 if (drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
6182 drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &pFlac->currentPCMFrame, NULL);
6183
6184 if (drflac__seek_to_pcm_frame__binary_search_internal(pFlac, pcmFrameIndex, byteRangeLo, byteRangeHi)) {
6185 return DRFLAC_TRUE;
6186 }
6187 }
6188 }
6189 }
6190#endif /* !DR_FLAC_NO_CRC */
6191
6192 /* Getting here means we need to use a slower algorithm because the binary search method failed or cannot be used. */
6193
6194 /*
6195 If we are seeking forward and the closest seekpoint is _before_ the current sample, we just seek forward from where we are. Otherwise we start seeking
6196 from the seekpoint's first sample.
6197 */
6198 if (pcmFrameIndex >= pFlac->currentPCMFrame && pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame <= pFlac->currentPCMFrame) {
6199 /* Optimized case. Just seek forward from where we are. */
6200 runningPCMFrameCount = pFlac->currentPCMFrame;
6201
6202 /* The frame header for the first frame may not yet have been read. We need to do that if necessary. */
6203 if (pFlac->currentPCMFrame == 0 && pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
6204 if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
6205 return DRFLAC_FALSE;
6206 }
6207 } else {
6208 isMidFrame = DRFLAC_TRUE;
6209 }
6210 } else {
6211 /* Slower case. Seek to the start of the seekpoint and then seek forward from there. */
6212 runningPCMFrameCount = pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame;
6213
6214 if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset)) {
6215 return DRFLAC_FALSE;
6216 }
6217
6218 /* Grab the frame the seekpoint is sitting on in preparation for the sample-exact seeking below. */
6219 if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
6220 return DRFLAC_FALSE;
6221 }
6222 }
6223
6224 for (;;) {
6225 drflac_uint64 pcmFrameCountInThisFLACFrame;
6226 drflac_uint64 firstPCMFrameInFLACFrame = 0;
6227 drflac_uint64 lastPCMFrameInFLACFrame = 0;
6228
6229 drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame);
6230
6231 pcmFrameCountInThisFLACFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1;
6232 if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFLACFrame)) {
6233 /*
6234 The sample should be in this frame. We need to fully decode it, but if it's an invalid frame (a CRC mismatch) we need to pretend
6235 it never existed and keep iterating.
6236 */
6237 drflac_uint64 pcmFramesToDecode = pcmFrameIndex - runningPCMFrameCount;
6238
6239 if (!isMidFrame) {
6240 drflac_result result = drflac__decode_flac_frame(pFlac);
6241 if (result == DRFLAC_SUCCESS) {
6242 /* The frame is valid. We just need to skip over some samples to ensure it's sample-exact. */
6243 return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; /* <-- If this fails, something bad has happened (it should never fail). */
6244 } else {
6245 if (result == DRFLAC_CRC_MISMATCH) {
6246 goto next_iteration; /* CRC mismatch. Pretend this frame never existed. */
6247 } else {
6248 return DRFLAC_FALSE;
6249 }
6250 }
6251 } else {
6252 /* We started seeking mid-frame which means we need to skip the frame decoding part. */
6253 return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode;
6254 }
6255 } else {
6256 /*
6257 It's not in this frame. We need to seek past the frame, but check if there was a CRC mismatch. If so, we pretend this
6258 frame never existed and leave the running sample count untouched.
6259 */
6260 if (!isMidFrame) {
6261 drflac_result result = drflac__seek_to_next_flac_frame(pFlac);
6262 if (result == DRFLAC_SUCCESS) {
6263 runningPCMFrameCount += pcmFrameCountInThisFLACFrame;
6264 } else {
6265 if (result == DRFLAC_CRC_MISMATCH) {
6266 goto next_iteration; /* CRC mismatch. Pretend this frame never existed. */
6267 } else {
6268 return DRFLAC_FALSE;
6269 }
6270 }
6271 } else {
6272 /*
6273 We started seeking mid-frame which means we need to seek by reading to the end of the frame instead of with
6274 drflac__seek_to_next_flac_frame() which only works if the decoder is sitting on the byte just after the frame header.
6275 */
6276 runningPCMFrameCount += pFlac->currentFLACFrame.pcmFramesRemaining;
6277 pFlac->currentFLACFrame.pcmFramesRemaining = 0;
6278 isMidFrame = DRFLAC_FALSE;
6279 }
6280
6281 /* If we are seeking to the end of the file and we've just hit it, we're done. */
6282 if (pcmFrameIndex == pFlac->totalPCMFrameCount && runningPCMFrameCount == pFlac->totalPCMFrameCount) {
6283 return DRFLAC_TRUE;
6284 }
6285 }
6286
6287 next_iteration:
6288 /* Grab the next frame in preparation for the next iteration. */
6289 if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
6290 return DRFLAC_FALSE;
6291 }
6292 }
6293}
6294
6295
6296#ifndef DR_FLAC_NO_OGG
6297typedef struct
6298{
6299 drflac_uint8 capturePattern[4]; /* Should be "OggS" */
6300 drflac_uint8 structureVersion; /* Always 0. */
6301 drflac_uint8 headerType;
6302 drflac_uint64 granulePosition;
6303 drflac_uint32 serialNumber;
6304 drflac_uint32 sequenceNumber;
6305 drflac_uint32 checksum;
6306 drflac_uint8 segmentCount;
6307 drflac_uint8 segmentTable[255];
6308} drflac_ogg_page_header;
6309#endif
6310
6311typedef struct
6312{
6313 drflac_read_proc onRead;
6314 drflac_seek_proc onSeek;
6315 drflac_meta_proc onMeta;
6316 drflac_container container;
6317 void* pUserData;
6318 void* pUserDataMD;
6319 drflac_uint32 sampleRate;
6320 drflac_uint8 channels;
6321 drflac_uint8 bitsPerSample;
6322 drflac_uint64 totalPCMFrameCount;
6323 drflac_uint16 maxBlockSizeInPCMFrames;
6324 drflac_uint64 runningFilePos;
6325 drflac_bool32 hasStreamInfoBlock;
6326 drflac_bool32 hasMetadataBlocks;
6327 drflac_bs bs; /* <-- A bit streamer is required for loading data during initialization. */
6328 drflac_frame_header firstFrameHeader; /* <-- The header of the first frame that was read during relaxed initalization. Only set if there is no STREAMINFO block. */
6329
6330#ifndef DR_FLAC_NO_OGG
6331 drflac_uint32 oggSerial;
6332 drflac_uint64 oggFirstBytePos;
6333 drflac_ogg_page_header oggBosHeader;
6334#endif
6335} drflac_init_info;
6336
6337static DRFLAC_INLINE void drflac__decode_block_header(drflac_uint32 blockHeader, drflac_uint8* isLastBlock, drflac_uint8* blockType, drflac_uint32* blockSize)
6338{
6339 blockHeader = drflac__be2host_32(blockHeader);
6340 *isLastBlock = (drflac_uint8)((blockHeader & 0x80000000UL) >> 31);
6341 *blockType = (drflac_uint8)((blockHeader & 0x7F000000UL) >> 24);
6342 *blockSize = (blockHeader & 0x00FFFFFFUL);
6343}
6344
6345static DRFLAC_INLINE drflac_bool32 drflac__read_and_decode_block_header(drflac_read_proc onRead, void* pUserData, drflac_uint8* isLastBlock, drflac_uint8* blockType, drflac_uint32* blockSize)
6346{
6347 drflac_uint32 blockHeader;
6348
6349 *blockSize = 0;
6350 if (onRead(pUserData, &blockHeader, 4) != 4) {
6351 return DRFLAC_FALSE;
6352 }
6353
6354 drflac__decode_block_header(blockHeader, isLastBlock, blockType, blockSize);
6355 return DRFLAC_TRUE;
6356}
6357
6358static drflac_bool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, drflac_streaminfo* pStreamInfo)
6359{
6360 drflac_uint32 blockSizes;
6361 drflac_uint64 frameSizes = 0;
6362 drflac_uint64 importantProps;
6363 drflac_uint8 md5[16];
6364
6365 /* min/max block size. */
6366 if (onRead(pUserData, &blockSizes, 4) != 4) {
6367 return DRFLAC_FALSE;
6368 }
6369
6370 /* min/max frame size. */
6371 if (onRead(pUserData, &frameSizes, 6) != 6) {
6372 return DRFLAC_FALSE;
6373 }
6374
6375 /* Sample rate, channels, bits per sample and total sample count. */
6376 if (onRead(pUserData, &importantProps, 8) != 8) {
6377 return DRFLAC_FALSE;
6378 }
6379
6380 /* MD5 */
6381 if (onRead(pUserData, md5, sizeof(md5)) != sizeof(md5)) {
6382 return DRFLAC_FALSE;
6383 }
6384
6385 blockSizes = drflac__be2host_32(blockSizes);
6386 frameSizes = drflac__be2host_64(frameSizes);
6387 importantProps = drflac__be2host_64(importantProps);
6388
6389 pStreamInfo->minBlockSizeInPCMFrames = (drflac_uint16)((blockSizes & 0xFFFF0000) >> 16);
6390 pStreamInfo->maxBlockSizeInPCMFrames = (drflac_uint16) (blockSizes & 0x0000FFFF);
6391 pStreamInfo->minFrameSizeInPCMFrames = (drflac_uint32)((frameSizes & (((drflac_uint64)0x00FFFFFF << 16) << 24)) >> 40);
6392 pStreamInfo->maxFrameSizeInPCMFrames = (drflac_uint32)((frameSizes & (((drflac_uint64)0x00FFFFFF << 16) << 0)) >> 16);
6393 pStreamInfo->sampleRate = (drflac_uint32)((importantProps & (((drflac_uint64)0x000FFFFF << 16) << 28)) >> 44);
6394 pStreamInfo->channels = (drflac_uint8 )((importantProps & (((drflac_uint64)0x0000000E << 16) << 24)) >> 41) + 1;
6395 pStreamInfo->bitsPerSample = (drflac_uint8 )((importantProps & (((drflac_uint64)0x0000001F << 16) << 20)) >> 36) + 1;
6396 pStreamInfo->totalPCMFrameCount = ((importantProps & ((((drflac_uint64)0x0000000F << 16) << 16) | 0xFFFFFFFF)));
6397 DRFLAC_COPY_MEMORY(pStreamInfo->md5, md5, sizeof(md5));
6398
6399 return DRFLAC_TRUE;
6400}
6401
6402
6403static void* drflac__malloc_default(size_t sz, void* pUserData)
6404{
6405 (void)pUserData;
6406 return DRFLAC_MALLOC(sz);
6407}
6408
6409static void* drflac__realloc_default(void* p, size_t sz, void* pUserData)
6410{
6411 (void)pUserData;
6412 return DRFLAC_REALLOC(p, sz);
6413}
6414
6415static void drflac__free_default(void* p, void* pUserData)
6416{
6417 (void)pUserData;
6418 DRFLAC_FREE(p);
6419}
6420
6421
6422static void* drflac__malloc_from_callbacks(size_t sz, const drflac_allocation_callbacks* pAllocationCallbacks)
6423{
6424 if (pAllocationCallbacks == NULL) {
6425 return NULL;
6426 }
6427
6428 if (pAllocationCallbacks->onMalloc != NULL) {
6429 return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData);
6430 }
6431
6432 /* Try using realloc(). */
6433 if (pAllocationCallbacks->onRealloc != NULL) {
6434 return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData);
6435 }
6436
6437 return NULL;
6438}
6439
6440static void* drflac__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drflac_allocation_callbacks* pAllocationCallbacks)
6441{
6442 if (pAllocationCallbacks == NULL) {
6443 return NULL;
6444 }
6445
6446 if (pAllocationCallbacks->onRealloc != NULL) {
6447 return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData);
6448 }
6449
6450 /* Try emulating realloc() in terms of malloc()/free(). */
6451 if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) {
6452 void* p2;
6453
6454 p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData);
6455 if (p2 == NULL) {
6456 return NULL;
6457 }
6458
6459 if (p != NULL) {
6460 DRFLAC_COPY_MEMORY(p2, p, szOld);
6461 pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
6462 }
6463
6464 return p2;
6465 }
6466
6467 return NULL;
6468}
6469
6470static void drflac__free_from_callbacks(void* p, const drflac_allocation_callbacks* pAllocationCallbacks)
6471{
6472 if (p == NULL || pAllocationCallbacks == NULL) {
6473 return;
6474 }
6475
6476 if (pAllocationCallbacks->onFree != NULL) {
6477 pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
6478 }
6479}
6480
6481
6482static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_uint64* pFirstFramePos, drflac_uint64* pSeektablePos, drflac_uint32* pSeekpointCount, drflac_allocation_callbacks* pAllocationCallbacks)
6483{
6484 /*
6485 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
6486 we'll be sitting on byte 42.
6487 */
6488 drflac_uint64 runningFilePos = 42;
6489 drflac_uint64 seektablePos = 0;
6490 drflac_uint32 seektableSize = 0;
6491
6492 for (;;) {
6493 drflac_metadata metadata;
6494 drflac_uint8 isLastBlock = 0;
6495 drflac_uint8 blockType = 0;
6496 drflac_uint32 blockSize;
6497 if (drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize) == DRFLAC_FALSE) {
6498 return DRFLAC_FALSE;
6499 }
6500 runningFilePos += 4;
6501
6502 metadata.type = blockType;
6503 metadata.pRawData = NULL;
6504 metadata.rawDataSize = 0;
6505
6506 switch (blockType)
6507 {
6508 case DRFLAC_METADATA_BLOCK_TYPE_APPLICATION:
6509 {
6510 if (blockSize < 4) {
6511 return DRFLAC_FALSE;
6512 }
6513
6514 if (onMeta) {
6515 void* pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
6516 if (pRawData == NULL) {
6517 return DRFLAC_FALSE;
6518 }
6519
6520 if (onRead(pUserData, pRawData, blockSize) != blockSize) {
6521 drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
6522 return DRFLAC_FALSE;
6523 }
6524
6525 metadata.pRawData = pRawData;
6526 metadata.rawDataSize = blockSize;
6527 metadata.data.application.id = drflac__be2host_32(*(drflac_uint32*)pRawData);
6528 metadata.data.application.pData = (const void*)((drflac_uint8*)pRawData + sizeof(drflac_uint32));
6529 metadata.data.application.dataSize = blockSize - sizeof(drflac_uint32);
6530 onMeta(pUserDataMD, &metadata);
6531
6532 drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
6533 }
6534 } break;
6535
6536 case DRFLAC_METADATA_BLOCK_TYPE_SEEKTABLE:
6537 {
6538 seektablePos = runningFilePos;
6539 seektableSize = blockSize;
6540
6541 if (onMeta) {
6542 drflac_uint32 seekpointCount;
6543 drflac_uint32 iSeekpoint;
6544 void* pRawData;
6545
6546 seekpointCount = blockSize/DRFLAC_SEEKPOINT_SIZE_IN_BYTES;
6547
6548 pRawData = drflac__malloc_from_callbacks(seekpointCount * sizeof(drflac_seekpoint), pAllocationCallbacks);
6549 if (pRawData == NULL) {
6550 return DRFLAC_FALSE;
6551 }
6552
6553 /* We need to read seekpoint by seekpoint and do some processing. */
6554 for (iSeekpoint = 0; iSeekpoint < seekpointCount; ++iSeekpoint) {
6555 drflac_seekpoint* pSeekpoint = (drflac_seekpoint*)pRawData + iSeekpoint;
6556
6557 if (onRead(pUserData, pSeekpoint, DRFLAC_SEEKPOINT_SIZE_IN_BYTES) != DRFLAC_SEEKPOINT_SIZE_IN_BYTES) {
6558 drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
6559 return DRFLAC_FALSE;
6560 }
6561
6562 /* Endian swap. */
6563 pSeekpoint->firstPCMFrame = drflac__be2host_64(pSeekpoint->firstPCMFrame);
6564 pSeekpoint->flacFrameOffset = drflac__be2host_64(pSeekpoint->flacFrameOffset);
6565 pSeekpoint->pcmFrameCount = drflac__be2host_16(pSeekpoint->pcmFrameCount);
6566 }
6567
6568 metadata.pRawData = pRawData;
6569 metadata.rawDataSize = blockSize;
6570 metadata.data.seektable.seekpointCount = seekpointCount;
6571 metadata.data.seektable.pSeekpoints = (const drflac_seekpoint*)pRawData;
6572
6573 onMeta(pUserDataMD, &metadata);
6574
6575 drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
6576 }
6577 } break;
6578
6579 case DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT:
6580 {
6581 if (blockSize < 8) {
6582 return DRFLAC_FALSE;
6583 }
6584
6585 if (onMeta) {
6586 void* pRawData;
6587 const char* pRunningData;
6588 const char* pRunningDataEnd;
6589 drflac_uint32 i;
6590
6591 pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
6592 if (pRawData == NULL) {
6593 return DRFLAC_FALSE;
6594 }
6595
6596 if (onRead(pUserData, pRawData, blockSize) != blockSize) {
6597 drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
6598 return DRFLAC_FALSE;
6599 }
6600
6601 metadata.pRawData = pRawData;
6602 metadata.rawDataSize = blockSize;
6603
6604 pRunningData = (const char*)pRawData;
6605 pRunningDataEnd = (const char*)pRawData + blockSize;
6606
6607 metadata.data.vorbis_comment.vendorLength = drflac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
6608
6609 /* Need space for the rest of the block */
6610 if ((pRunningDataEnd - pRunningData) - 4 < (drflac_int64)metadata.data.vorbis_comment.vendorLength) { /* <-- Note the order of operations to avoid overflow to a valid value */
6611 drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
6612 return DRFLAC_FALSE;
6613 }
6614 metadata.data.vorbis_comment.vendor = pRunningData; pRunningData += metadata.data.vorbis_comment.vendorLength;
6615 metadata.data.vorbis_comment.commentCount = drflac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
6616
6617 /* Need space for 'commentCount' comments after the block, which at minimum is a drflac_uint32 per comment */
6618 if ((pRunningDataEnd - pRunningData) / sizeof(drflac_uint32) < metadata.data.vorbis_comment.commentCount) { /* <-- Note the order of operations to avoid overflow to a valid value */
6619 drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
6620 return DRFLAC_FALSE;
6621 }
6622 metadata.data.vorbis_comment.pComments = pRunningData;
6623
6624 /* Check that the comments section is valid before passing it to the callback */
6625 for (i = 0; i < metadata.data.vorbis_comment.commentCount; ++i) {
6626 drflac_uint32 commentLength;
6627
6628 if (pRunningDataEnd - pRunningData < 4) {
6629 drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
6630 return DRFLAC_FALSE;
6631 }
6632
6633 commentLength = drflac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
6634 if (pRunningDataEnd - pRunningData < (drflac_int64)commentLength) { /* <-- Note the order of operations to avoid overflow to a valid value */
6635 drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
6636 return DRFLAC_FALSE;
6637 }
6638 pRunningData += commentLength;
6639 }
6640
6641 onMeta(pUserDataMD, &metadata);
6642
6643 drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
6644 }
6645 } break;
6646
6647 case DRFLAC_METADATA_BLOCK_TYPE_CUESHEET:
6648 {
6649 if (blockSize < 396) {
6650 return DRFLAC_FALSE;
6651 }
6652
6653 if (onMeta) {
6654 void* pRawData;
6655 const char* pRunningData;
6656 const char* pRunningDataEnd;
6657 size_t bufferSize;
6658 drflac_uint8 iTrack;
6659 drflac_uint8 iIndex;
6660 void* pTrackData;
6661
6662 /*
6663 This needs to be loaded in two passes. The first pass is used to calculate the size of the memory allocation
6664 we need for storing the necessary data. The second pass will fill that buffer with usable data.
6665 */
6666 pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
6667 if (pRawData == NULL) {
6668 return DRFLAC_FALSE;
6669 }
6670
6671 if (onRead(pUserData, pRawData, blockSize) != blockSize) {
6672 drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
6673 return DRFLAC_FALSE;
6674 }
6675
6676 metadata.pRawData = pRawData;
6677 metadata.rawDataSize = blockSize;
6678
6679 pRunningData = (const char*)pRawData;
6680 pRunningDataEnd = (const char*)pRawData + blockSize;
6681
6682 DRFLAC_COPY_MEMORY(metadata.data.cuesheet.catalog, pRunningData, 128); pRunningData += 128;
6683 metadata.data.cuesheet.leadInSampleCount = drflac__be2host_64(*(const drflac_uint64*)pRunningData); pRunningData += 8;
6684 metadata.data.cuesheet.isCD = (pRunningData[0] & 0x80) != 0; pRunningData += 259;
6685 metadata.data.cuesheet.trackCount = pRunningData[0]; pRunningData += 1;
6686 metadata.data.cuesheet.pTrackData = NULL; /* Will be filled later. */
6687
6688 /* Pass 1: Calculate the size of the buffer for the track data. */
6689 {
6690 const char* pRunningDataSaved = pRunningData; /* Will be restored at the end in preparation for the second pass. */
6691
6692 bufferSize = metadata.data.cuesheet.trackCount * DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES;
6693
6694 for (iTrack = 0; iTrack < metadata.data.cuesheet.trackCount; ++iTrack) {
6695 drflac_uint8 indexCount;
6696 drflac_uint32 indexPointSize;
6697
6698 if (pRunningDataEnd - pRunningData < DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES) {
6699 drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
6700 return DRFLAC_FALSE;
6701 }
6702
6703 /* Skip to the index point count */
6704 pRunningData += 35;
6705
6706 indexCount = pRunningData[0];
6707 pRunningData += 1;
6708
6709 bufferSize += indexCount * sizeof(drflac_cuesheet_track_index);
6710
6711 /* Quick validation check. */
6712 indexPointSize = indexCount * DRFLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES;
6713 if (pRunningDataEnd - pRunningData < (drflac_int64)indexPointSize) {
6714 drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
6715 return DRFLAC_FALSE;
6716 }
6717
6718 pRunningData += indexPointSize;
6719 }
6720
6721 pRunningData = pRunningDataSaved;
6722 }
6723
6724 /* Pass 2: Allocate a buffer and fill the data. Validation was done in the step above so can be skipped. */
6725 {
6726 char* pRunningTrackData;
6727
6728 pTrackData = drflac__malloc_from_callbacks(bufferSize, pAllocationCallbacks);
6729 if (pTrackData == NULL) {
6730 drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
6731 return DRFLAC_FALSE;
6732 }
6733
6734 pRunningTrackData = (char*)pTrackData;
6735
6736 for (iTrack = 0; iTrack < metadata.data.cuesheet.trackCount; ++iTrack) {
6737 drflac_uint8 indexCount;
6738
6739 DRFLAC_COPY_MEMORY(pRunningTrackData, pRunningData, DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES);
6740 pRunningData += DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES-1; /* Skip forward, but not beyond the last byte in the CUESHEET_TRACK block which is the index count. */
6741 pRunningTrackData += DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES-1;
6742
6743 /* Grab the index count for the next part. */
6744 indexCount = pRunningData[0];
6745 pRunningData += 1;
6746 pRunningTrackData += 1;
6747
6748 /* Extract each track index. */
6749 for (iIndex = 0; iIndex < indexCount; ++iIndex) {
6750 drflac_cuesheet_track_index* pTrackIndex = (drflac_cuesheet_track_index*)pRunningTrackData;
6751
6752 DRFLAC_COPY_MEMORY(pRunningTrackData, pRunningData, DRFLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES);
6753 pRunningData += DRFLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES;
6754 pRunningTrackData += sizeof(drflac_cuesheet_track_index);
6755
6756 pTrackIndex->offset = drflac__be2host_64(pTrackIndex->offset);
6757 }
6758 }
6759
6760 metadata.data.cuesheet.pTrackData = pTrackData;
6761 }
6762
6763 /* The original data is no longer needed. */
6764 drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
6765 pRawData = NULL;
6766
6767 onMeta(pUserDataMD, &metadata);
6768
6769 drflac__free_from_callbacks(pTrackData, pAllocationCallbacks);
6770 pTrackData = NULL;
6771 }
6772 } break;
6773
6774 case DRFLAC_METADATA_BLOCK_TYPE_PICTURE:
6775 {
6776 if (blockSize < 32) {
6777 return DRFLAC_FALSE;
6778 }
6779
6780 if (onMeta) {
6781 void* pRawData;
6782 const char* pRunningData;
6783 const char* pRunningDataEnd;
6784
6785 pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
6786 if (pRawData == NULL) {
6787 return DRFLAC_FALSE;
6788 }
6789
6790 if (onRead(pUserData, pRawData, blockSize) != blockSize) {
6791 drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
6792 return DRFLAC_FALSE;
6793 }
6794
6795 metadata.pRawData = pRawData;
6796 metadata.rawDataSize = blockSize;
6797
6798 pRunningData = (const char*)pRawData;
6799 pRunningDataEnd = (const char*)pRawData + blockSize;
6800
6801 metadata.data.picture.type = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
6802 metadata.data.picture.mimeLength = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
6803
6804 /* Need space for the rest of the block */
6805 if ((pRunningDataEnd - pRunningData) - 24 < (drflac_int64)metadata.data.picture.mimeLength) { /* <-- Note the order of operations to avoid overflow to a valid value */
6806 drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
6807 return DRFLAC_FALSE;
6808 }
6809 metadata.data.picture.mime = pRunningData; pRunningData += metadata.data.picture.mimeLength;
6810 metadata.data.picture.descriptionLength = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
6811
6812 /* Need space for the rest of the block */
6813 if ((pRunningDataEnd - pRunningData) - 20 < (drflac_int64)metadata.data.picture.descriptionLength) { /* <-- Note the order of operations to avoid overflow to a valid value */
6814 drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
6815 return DRFLAC_FALSE;
6816 }
6817 metadata.data.picture.description = pRunningData; pRunningData += metadata.data.picture.descriptionLength;
6818 metadata.data.picture.width = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
6819 metadata.data.picture.height = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
6820 metadata.data.picture.colorDepth = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
6821 metadata.data.picture.indexColorCount = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
6822 metadata.data.picture.pictureDataSize = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4;
6823 metadata.data.picture.pPictureData = (const drflac_uint8*)pRunningData;
6824
6825 /* Need space for the picture after the block */
6826 if (pRunningDataEnd - pRunningData < (drflac_int64)metadata.data.picture.pictureDataSize) { /* <-- Note the order of operations to avoid overflow to a valid value */
6827 drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
6828 return DRFLAC_FALSE;
6829 }
6830
6831 onMeta(pUserDataMD, &metadata);
6832
6833 drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
6834 }
6835 } break;
6836
6837 case DRFLAC_METADATA_BLOCK_TYPE_PADDING:
6838 {
6839 if (onMeta) {
6840 metadata.data.padding.unused = 0;
6841
6842 /* Padding doesn't have anything meaningful in it, so just skip over it, but make sure the caller is aware of it by firing the callback. */
6843 if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) {
6844 isLastBlock = DRFLAC_TRUE; /* An error occurred while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. */
6845 } else {
6846 onMeta(pUserDataMD, &metadata);
6847 }
6848 }
6849 } break;
6850
6851 case DRFLAC_METADATA_BLOCK_TYPE_INVALID:
6852 {
6853 /* Invalid chunk. Just skip over this one. */
6854 if (onMeta) {
6855 if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) {
6856 isLastBlock = DRFLAC_TRUE; /* An error occurred while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. */
6857 }
6858 }
6859 } break;
6860
6861 default:
6862 {
6863 /*
6864 It's an unknown chunk, but not necessarily invalid. There's a chance more metadata blocks might be defined later on, so we
6865 can at the very least report the chunk to the application and let it look at the raw data.
6866 */
6867 if (onMeta) {
6868 void* pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
6869 if (pRawData == NULL) {
6870 return DRFLAC_FALSE;
6871 }
6872
6873 if (onRead(pUserData, pRawData, blockSize) != blockSize) {
6874 drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
6875 return DRFLAC_FALSE;
6876 }
6877
6878 metadata.pRawData = pRawData;
6879 metadata.rawDataSize = blockSize;
6880 onMeta(pUserDataMD, &metadata);
6881
6882 drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
6883 }
6884 } break;
6885 }
6886
6887 /* 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. */
6888 if (onMeta == NULL && blockSize > 0) {
6889 if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) {
6890 isLastBlock = DRFLAC_TRUE;
6891 }
6892 }
6893
6894 runningFilePos += blockSize;
6895 if (isLastBlock) {
6896 break;
6897 }
6898 }
6899
6900 *pSeektablePos = seektablePos;
6901 *pSeekpointCount = seektableSize / DRFLAC_SEEKPOINT_SIZE_IN_BYTES;
6902 *pFirstFramePos = runningFilePos;
6903
6904 return DRFLAC_TRUE;
6905}
6906
6907static drflac_bool32 drflac__init_private__native(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_bool32 relaxed)
6908{
6909 /* Pre Condition: The bit stream should be sitting just past the 4-byte id header. */
6910
6911 drflac_uint8 isLastBlock;
6912 drflac_uint8 blockType;
6913 drflac_uint32 blockSize;
6914
6915 (void)onSeek;
6916
6917 pInit->container = drflac_container_native;
6918
6919 /* The first metadata block should be the STREAMINFO block. */
6920 if (!drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize)) {
6921 return DRFLAC_FALSE;
6922 }
6923
6924 if (blockType != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) {
6925 if (!relaxed) {
6926 /* We're opening in strict mode and the first block is not the STREAMINFO block. Error. */
6927 return DRFLAC_FALSE;
6928 } else {
6929 /*
6930 Relaxed mode. To open from here we need to just find the first frame and set the sample rate, etc. to whatever is defined
6931 for that frame.
6932 */
6933 pInit->hasStreamInfoBlock = DRFLAC_FALSE;
6934 pInit->hasMetadataBlocks = DRFLAC_FALSE;
6935
6936 if (!drflac__read_next_flac_frame_header(&pInit->bs, 0, &pInit->firstFrameHeader)) {
6937 return DRFLAC_FALSE; /* Couldn't find a frame. */
6938 }
6939
6940 if (pInit->firstFrameHeader.bitsPerSample == 0) {
6941 return DRFLAC_FALSE; /* Failed to initialize because the first frame depends on the STREAMINFO block, which does not exist. */
6942 }
6943
6944 pInit->sampleRate = pInit->firstFrameHeader.sampleRate;
6945 pInit->channels = drflac__get_channel_count_from_channel_assignment(pInit->firstFrameHeader.channelAssignment);
6946 pInit->bitsPerSample = pInit->firstFrameHeader.bitsPerSample;
6947 pInit->maxBlockSizeInPCMFrames = 65535; /* <-- See notes here: https://xiph.org/flac/format.html#metadata_block_streaminfo */
6948 return DRFLAC_TRUE;
6949 }
6950 } else {
6951 drflac_streaminfo streaminfo;
6952 if (!drflac__read_streaminfo(onRead, pUserData, &streaminfo)) {
6953 return DRFLAC_FALSE;
6954 }
6955
6956 pInit->hasStreamInfoBlock = DRFLAC_TRUE;
6957 pInit->sampleRate = streaminfo.sampleRate;
6958 pInit->channels = streaminfo.channels;
6959 pInit->bitsPerSample = streaminfo.bitsPerSample;
6960 pInit->totalPCMFrameCount = streaminfo.totalPCMFrameCount;
6961 pInit->maxBlockSizeInPCMFrames = streaminfo.maxBlockSizeInPCMFrames; /* Don't care about the min block size - only the max (used for determining the size of the memory allocation). */
6962 pInit->hasMetadataBlocks = !isLastBlock;
6963
6964 if (onMeta) {
6965 drflac_metadata metadata;
6966 metadata.type = DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO;
6967 metadata.pRawData = NULL;
6968 metadata.rawDataSize = 0;
6969 metadata.data.streaminfo = streaminfo;
6970 onMeta(pUserDataMD, &metadata);
6971 }
6972
6973 return DRFLAC_TRUE;
6974 }
6975}
6976
6977#ifndef DR_FLAC_NO_OGG
6978#define DRFLAC_OGG_MAX_PAGE_SIZE 65307
6979#define DRFLAC_OGG_CAPTURE_PATTERN_CRC32 1605413199 /* CRC-32 of "OggS". */
6980
6981typedef enum
6982{
6983 drflac_ogg_recover_on_crc_mismatch,
6984 drflac_ogg_fail_on_crc_mismatch
6985} drflac_ogg_crc_mismatch_recovery;
6986
6987#ifndef DR_FLAC_NO_CRC
6988static drflac_uint32 drflac__crc32_table[] = {
6989 0x00000000L, 0x04C11DB7L, 0x09823B6EL, 0x0D4326D9L,
6990 0x130476DCL, 0x17C56B6BL, 0x1A864DB2L, 0x1E475005L,
6991 0x2608EDB8L, 0x22C9F00FL, 0x2F8AD6D6L, 0x2B4BCB61L,
6992 0x350C9B64L, 0x31CD86D3L, 0x3C8EA00AL, 0x384FBDBDL,
6993 0x4C11DB70L, 0x48D0C6C7L, 0x4593E01EL, 0x4152FDA9L,
6994 0x5F15ADACL, 0x5BD4B01BL, 0x569796C2L, 0x52568B75L,
6995 0x6A1936C8L, 0x6ED82B7FL, 0x639B0DA6L, 0x675A1011L,
6996 0x791D4014L, 0x7DDC5DA3L, 0x709F7B7AL, 0x745E66CDL,
6997 0x9823B6E0L, 0x9CE2AB57L, 0x91A18D8EL, 0x95609039L,
6998 0x8B27C03CL, 0x8FE6DD8BL, 0x82A5FB52L, 0x8664E6E5L,
6999 0xBE2B5B58L, 0xBAEA46EFL, 0xB7A96036L, 0xB3687D81L,
7000 0xAD2F2D84L, 0xA9EE3033L, 0xA4AD16EAL, 0xA06C0B5DL,
7001 0xD4326D90L, 0xD0F37027L, 0xDDB056FEL, 0xD9714B49L,
7002 0xC7361B4CL, 0xC3F706FBL, 0xCEB42022L, 0xCA753D95L,
7003 0xF23A8028L, 0xF6FB9D9FL, 0xFBB8BB46L, 0xFF79A6F1L,
7004 0xE13EF6F4L, 0xE5FFEB43L, 0xE8BCCD9AL, 0xEC7DD02DL,
7005 0x34867077L, 0x30476DC0L, 0x3D044B19L, 0x39C556AEL,
7006 0x278206ABL, 0x23431B1CL, 0x2E003DC5L, 0x2AC12072L,
7007 0x128E9DCFL, 0x164F8078L, 0x1B0CA6A1L, 0x1FCDBB16L,
7008 0x018AEB13L, 0x054BF6A4L, 0x0808D07DL, 0x0CC9CDCAL,
7009 0x7897AB07L, 0x7C56B6B0L, 0x71159069L, 0x75D48DDEL,
7010 0x6B93DDDBL, 0x6F52C06CL, 0x6211E6B5L, 0x66D0FB02L,
7011 0x5E9F46BFL, 0x5A5E5B08L, 0x571D7DD1L, 0x53DC6066L,
7012 0x4D9B3063L, 0x495A2DD4L, 0x44190B0DL, 0x40D816BAL,
7013 0xACA5C697L, 0xA864DB20L, 0xA527FDF9L, 0xA1E6E04EL,
7014 0xBFA1B04BL, 0xBB60ADFCL, 0xB6238B25L, 0xB2E29692L,
7015 0x8AAD2B2FL, 0x8E6C3698L, 0x832F1041L, 0x87EE0DF6L,
7016 0x99A95DF3L, 0x9D684044L, 0x902B669DL, 0x94EA7B2AL,
7017 0xE0B41DE7L, 0xE4750050L, 0xE9362689L, 0xEDF73B3EL,
7018 0xF3B06B3BL, 0xF771768CL, 0xFA325055L, 0xFEF34DE2L,
7019 0xC6BCF05FL, 0xC27DEDE8L, 0xCF3ECB31L, 0xCBFFD686L,
7020 0xD5B88683L, 0xD1799B34L, 0xDC3ABDEDL, 0xD8FBA05AL,
7021 0x690CE0EEL, 0x6DCDFD59L, 0x608EDB80L, 0x644FC637L,
7022 0x7A089632L, 0x7EC98B85L, 0x738AAD5CL, 0x774BB0EBL,
7023 0x4F040D56L, 0x4BC510E1L, 0x46863638L, 0x42472B8FL,
7024 0x5C007B8AL, 0x58C1663DL, 0x558240E4L, 0x51435D53L,
7025 0x251D3B9EL, 0x21DC2629L, 0x2C9F00F0L, 0x285E1D47L,
7026 0x36194D42L, 0x32D850F5L, 0x3F9B762CL, 0x3B5A6B9BL,
7027 0x0315D626L, 0x07D4CB91L, 0x0A97ED48L, 0x0E56F0FFL,
7028 0x1011A0FAL, 0x14D0BD4DL, 0x19939B94L, 0x1D528623L,
7029 0xF12F560EL, 0xF5EE4BB9L, 0xF8AD6D60L, 0xFC6C70D7L,
7030 0xE22B20D2L, 0xE6EA3D65L, 0xEBA91BBCL, 0xEF68060BL,
7031 0xD727BBB6L, 0xD3E6A601L, 0xDEA580D8L, 0xDA649D6FL,
7032 0xC423CD6AL, 0xC0E2D0DDL, 0xCDA1F604L, 0xC960EBB3L,
7033 0xBD3E8D7EL, 0xB9FF90C9L, 0xB4BCB610L, 0xB07DABA7L,
7034 0xAE3AFBA2L, 0xAAFBE615L, 0xA7B8C0CCL, 0xA379DD7BL,
7035 0x9B3660C6L, 0x9FF77D71L, 0x92B45BA8L, 0x9675461FL,
7036 0x8832161AL, 0x8CF30BADL, 0x81B02D74L, 0x857130C3L,
7037 0x5D8A9099L, 0x594B8D2EL, 0x5408ABF7L, 0x50C9B640L,
7038 0x4E8EE645L, 0x4A4FFBF2L, 0x470CDD2BL, 0x43CDC09CL,
7039 0x7B827D21L, 0x7F436096L, 0x7200464FL, 0x76C15BF8L,
7040 0x68860BFDL, 0x6C47164AL, 0x61043093L, 0x65C52D24L,
7041 0x119B4BE9L, 0x155A565EL, 0x18197087L, 0x1CD86D30L,
7042 0x029F3D35L, 0x065E2082L, 0x0B1D065BL, 0x0FDC1BECL,
7043 0x3793A651L, 0x3352BBE6L, 0x3E119D3FL, 0x3AD08088L,
7044 0x2497D08DL, 0x2056CD3AL, 0x2D15EBE3L, 0x29D4F654L,
7045 0xC5A92679L, 0xC1683BCEL, 0xCC2B1D17L, 0xC8EA00A0L,
7046 0xD6AD50A5L, 0xD26C4D12L, 0xDF2F6BCBL, 0xDBEE767CL,
7047 0xE3A1CBC1L, 0xE760D676L, 0xEA23F0AFL, 0xEEE2ED18L,
7048 0xF0A5BD1DL, 0xF464A0AAL, 0xF9278673L, 0xFDE69BC4L,
7049 0x89B8FD09L, 0x8D79E0BEL, 0x803AC667L, 0x84FBDBD0L,
7050 0x9ABC8BD5L, 0x9E7D9662L, 0x933EB0BBL, 0x97FFAD0CL,
7051 0xAFB010B1L, 0xAB710D06L, 0xA6322BDFL, 0xA2F33668L,
7052 0xBCB4666DL, 0xB8757BDAL, 0xB5365D03L, 0xB1F740B4L
7053};
7054#endif
7055
7056static DRFLAC_INLINE drflac_uint32 drflac_crc32_byte(drflac_uint32 crc32, drflac_uint8 data)
7057{
7058#ifndef DR_FLAC_NO_CRC
7059 return (crc32 << 8) ^ drflac__crc32_table[(drflac_uint8)((crc32 >> 24) & 0xFF) ^ data];
7060#else
7061 (void)data;
7062 return crc32;
7063#endif
7064}
7065
7066#if 0
7067static DRFLAC_INLINE drflac_uint32 drflac_crc32_uint32(drflac_uint32 crc32, drflac_uint32 data)
7068{
7069 crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 24) & 0xFF));
7070 crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 16) & 0xFF));
7071 crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 8) & 0xFF));
7072 crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 0) & 0xFF));
7073 return crc32;
7074}
7075
7076static DRFLAC_INLINE drflac_uint32 drflac_crc32_uint64(drflac_uint32 crc32, drflac_uint64 data)
7077{
7078 crc32 = drflac_crc32_uint32(crc32, (drflac_uint32)((data >> 32) & 0xFFFFFFFF));
7079 crc32 = drflac_crc32_uint32(crc32, (drflac_uint32)((data >> 0) & 0xFFFFFFFF));
7080 return crc32;
7081}
7082#endif
7083
7084static DRFLAC_INLINE drflac_uint32 drflac_crc32_buffer(drflac_uint32 crc32, drflac_uint8* pData, drflac_uint32 dataSize)
7085{
7086 /* This can be optimized. */
7087 drflac_uint32 i;
7088 for (i = 0; i < dataSize; ++i) {
7089 crc32 = drflac_crc32_byte(crc32, pData[i]);
7090 }
7091 return crc32;
7092}
7093
7094
7095static DRFLAC_INLINE drflac_bool32 drflac_ogg__is_capture_pattern(drflac_uint8 pattern[4])
7096{
7097 return pattern[0] == 'O' && pattern[1] == 'g' && pattern[2] == 'g' && pattern[3] == 'S';
7098}
7099
7100static DRFLAC_INLINE drflac_uint32 drflac_ogg__get_page_header_size(drflac_ogg_page_header* pHeader)
7101{
7102 return 27 + pHeader->segmentCount;
7103}
7104
7105static DRFLAC_INLINE drflac_uint32 drflac_ogg__get_page_body_size(drflac_ogg_page_header* pHeader)
7106{
7107 drflac_uint32 pageBodySize = 0;
7108 int i;
7109
7110 for (i = 0; i < pHeader->segmentCount; ++i) {
7111 pageBodySize += pHeader->segmentTable[i];
7112 }
7113
7114 return pageBodySize;
7115}
7116
7117static drflac_result drflac_ogg__read_page_header_after_capture_pattern(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, drflac_uint32* pBytesRead, drflac_uint32* pCRC32)
7118{
7119 drflac_uint8 data[23];
7120 drflac_uint32 i;
7121
7122 DRFLAC_ASSERT(*pCRC32 == DRFLAC_OGG_CAPTURE_PATTERN_CRC32);
7123
7124 if (onRead(pUserData, data, 23) != 23) {
7125 return DRFLAC_AT_END;
7126 }
7127 *pBytesRead += 23;
7128
7129 /*
7130 It's not actually used, but set the capture pattern to 'OggS' for completeness. Not doing this will cause static analysers to complain about
7131 us trying to access uninitialized data. We could alternatively just comment out this member of the drflac_ogg_page_header structure, but I
7132 like to have it map to the structure of the underlying data.
7133 */
7134 pHeader->capturePattern[0] = 'O';
7135 pHeader->capturePattern[1] = 'g';
7136 pHeader->capturePattern[2] = 'g';
7137 pHeader->capturePattern[3] = 'S';
7138
7139 pHeader->structureVersion = data[0];
7140 pHeader->headerType = data[1];
7141 DRFLAC_COPY_MEMORY(&pHeader->granulePosition, &data[ 2], 8);
7142 DRFLAC_COPY_MEMORY(&pHeader->serialNumber, &data[10], 4);
7143 DRFLAC_COPY_MEMORY(&pHeader->sequenceNumber, &data[14], 4);
7144 DRFLAC_COPY_MEMORY(&pHeader->checksum, &data[18], 4);
7145 pHeader->segmentCount = data[22];
7146
7147 /* Calculate the CRC. Note that for the calculation the checksum part of the page needs to be set to 0. */
7148 data[18] = 0;
7149 data[19] = 0;
7150 data[20] = 0;
7151 data[21] = 0;
7152
7153 for (i = 0; i < 23; ++i) {
7154 *pCRC32 = drflac_crc32_byte(*pCRC32, data[i]);
7155 }
7156
7157
7158 if (onRead(pUserData, pHeader->segmentTable, pHeader->segmentCount) != pHeader->segmentCount) {
7159 return DRFLAC_AT_END;
7160 }
7161 *pBytesRead += pHeader->segmentCount;
7162
7163 for (i = 0; i < pHeader->segmentCount; ++i) {
7164 *pCRC32 = drflac_crc32_byte(*pCRC32, pHeader->segmentTable[i]);
7165 }
7166
7167 return DRFLAC_SUCCESS;
7168}
7169
7170static drflac_result drflac_ogg__read_page_header(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, drflac_uint32* pBytesRead, drflac_uint32* pCRC32)
7171{
7172 drflac_uint8 id[4];
7173
7174 *pBytesRead = 0;
7175
7176 if (onRead(pUserData, id, 4) != 4) {
7177 return DRFLAC_AT_END;
7178 }
7179 *pBytesRead += 4;
7180
7181 /* We need to read byte-by-byte until we find the OggS capture pattern. */
7182 for (;;) {
7183 if (drflac_ogg__is_capture_pattern(id)) {
7184 drflac_result result;
7185
7186 *pCRC32 = DRFLAC_OGG_CAPTURE_PATTERN_CRC32;
7187
7188 result = drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, pHeader, pBytesRead, pCRC32);
7189 if (result == DRFLAC_SUCCESS) {
7190 return DRFLAC_SUCCESS;
7191 } else {
7192 if (result == DRFLAC_CRC_MISMATCH) {
7193 continue;
7194 } else {
7195 return result;
7196 }
7197 }
7198 } else {
7199 /* The first 4 bytes did not equal the capture pattern. Read the next byte and try again. */
7200 id[0] = id[1];
7201 id[1] = id[2];
7202 id[2] = id[3];
7203 if (onRead(pUserData, &id[3], 1) != 1) {
7204 return DRFLAC_AT_END;
7205 }
7206 *pBytesRead += 1;
7207 }
7208 }
7209}
7210
7211
7212/*
7213The main part of the Ogg encapsulation is the conversion from the physical Ogg bitstream to the native FLAC bitstream. It works
7214in three general stages: Ogg Physical Bitstream -> Ogg/FLAC Logical Bitstream -> FLAC Native Bitstream. dr_flac is designed
7215in such a way that the core sections assume everything is delivered in native format. Therefore, for each encapsulation type
7216dr_flac is supporting there needs to be a layer sitting on top of the onRead and onSeek callbacks that ensures the bits read from
7217the physical Ogg bitstream are converted and delivered in native FLAC format.
7218*/
7219typedef struct
7220{
7221 drflac_read_proc onRead; /* The original onRead callback from drflac_open() and family. */
7222 drflac_seek_proc onSeek; /* The original onSeek callback from drflac_open() and family. */
7223 void* pUserData; /* The user data passed on onRead and onSeek. This is the user data that was passed on drflac_open() and family. */
7224 drflac_uint64 currentBytePos; /* The position of the byte we are sitting on in the physical byte stream. Used for efficient seeking. */
7225 drflac_uint64 firstBytePos; /* The position of the first byte in the physical bitstream. Points to the start of the "OggS" identifier of the FLAC bos page. */
7226 drflac_uint32 serialNumber; /* The serial number of the FLAC audio pages. This is determined by the initial header page that was read during initialization. */
7227 drflac_ogg_page_header bosPageHeader; /* Used for seeking. */
7228 drflac_ogg_page_header currentPageHeader;
7229 drflac_uint32 bytesRemainingInPage;
7230 drflac_uint32 pageDataSize;
7231 drflac_uint8 pageData[DRFLAC_OGG_MAX_PAGE_SIZE];
7232} drflac_oggbs; /* oggbs = Ogg Bitstream */
7233
7234static size_t drflac_oggbs__read_physical(drflac_oggbs* oggbs, void* bufferOut, size_t bytesToRead)
7235{
7236 size_t bytesActuallyRead = oggbs->onRead(oggbs->pUserData, bufferOut, bytesToRead);
7237 oggbs->currentBytePos += bytesActuallyRead;
7238
7239 return bytesActuallyRead;
7240}
7241
7242static drflac_bool32 drflac_oggbs__seek_physical(drflac_oggbs* oggbs, drflac_uint64 offset, drflac_seek_origin origin)
7243{
7244 if (origin == drflac_seek_origin_start) {
7245 if (offset <= 0x7FFFFFFF) {
7246 if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_start)) {
7247 return DRFLAC_FALSE;
7248 }
7249 oggbs->currentBytePos = offset;
7250
7251 return DRFLAC_TRUE;
7252 } else {
7253 if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) {
7254 return DRFLAC_FALSE;
7255 }
7256 oggbs->currentBytePos = offset;
7257
7258 return drflac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, drflac_seek_origin_current);
7259 }
7260 } else {
7261 while (offset > 0x7FFFFFFF) {
7262 if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, drflac_seek_origin_current)) {
7263 return DRFLAC_FALSE;
7264 }
7265 oggbs->currentBytePos += 0x7FFFFFFF;
7266 offset -= 0x7FFFFFFF;
7267 }
7268
7269 if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_current)) { /* <-- Safe cast thanks to the loop above. */
7270 return DRFLAC_FALSE;
7271 }
7272 oggbs->currentBytePos += offset;
7273
7274 return DRFLAC_TRUE;
7275 }
7276}
7277
7278static drflac_bool32 drflac_oggbs__goto_next_page(drflac_oggbs* oggbs, drflac_ogg_crc_mismatch_recovery recoveryMethod)
7279{
7280 drflac_ogg_page_header header;
7281 for (;;) {
7282 drflac_uint32 crc32 = 0;
7283 drflac_uint32 bytesRead;
7284 drflac_uint32 pageBodySize;
7285#ifndef DR_FLAC_NO_CRC
7286 drflac_uint32 actualCRC32;
7287#endif
7288
7289 if (drflac_ogg__read_page_header(oggbs->onRead, oggbs->pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) {
7290 return DRFLAC_FALSE;
7291 }
7292 oggbs->currentBytePos += bytesRead;
7293
7294 pageBodySize = drflac_ogg__get_page_body_size(&header);
7295 if (pageBodySize > DRFLAC_OGG_MAX_PAGE_SIZE) {
7296 continue; /* Invalid page size. Assume it's corrupted and just move to the next page. */
7297 }
7298
7299 if (header.serialNumber != oggbs->serialNumber) {
7300 /* It's not a FLAC page. Skip it. */
7301 if (pageBodySize > 0 && !drflac_oggbs__seek_physical(oggbs, pageBodySize, drflac_seek_origin_current)) {
7302 return DRFLAC_FALSE;
7303 }
7304 continue;
7305 }
7306
7307
7308 /* We need to read the entire page and then do a CRC check on it. If there's a CRC mismatch we need to skip this page. */
7309 if (drflac_oggbs__read_physical(oggbs, oggbs->pageData, pageBodySize) != pageBodySize) {
7310 return DRFLAC_FALSE;
7311 }
7312 oggbs->pageDataSize = pageBodySize;
7313
7314#ifndef DR_FLAC_NO_CRC
7315 actualCRC32 = drflac_crc32_buffer(crc32, oggbs->pageData, oggbs->pageDataSize);
7316 if (actualCRC32 != header.checksum) {
7317 if (recoveryMethod == drflac_ogg_recover_on_crc_mismatch) {
7318 continue; /* CRC mismatch. Skip this page. */
7319 } else {
7320 /*
7321 Even though we are failing on a CRC mismatch, we still want our stream to be in a good state. Therefore we
7322 go to the next valid page to ensure we're in a good state, but return false to let the caller know that the
7323 seek did not fully complete.
7324 */
7325 drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch);
7326 return DRFLAC_FALSE;
7327 }
7328 }
7329#else
7330 (void)recoveryMethod; /* <-- Silence a warning. */
7331#endif
7332
7333 oggbs->currentPageHeader = header;
7334 oggbs->bytesRemainingInPage = pageBodySize;
7335 return DRFLAC_TRUE;
7336 }
7337}
7338
7339/* Function below is unused at the moment, but I might be re-adding it later. */
7340#if 0
7341static drflac_uint8 drflac_oggbs__get_current_segment_index(drflac_oggbs* oggbs, drflac_uint8* pBytesRemainingInSeg)
7342{
7343 drflac_uint32 bytesConsumedInPage = drflac_ogg__get_page_body_size(&oggbs->currentPageHeader) - oggbs->bytesRemainingInPage;
7344 drflac_uint8 iSeg = 0;
7345 drflac_uint32 iByte = 0;
7346 while (iByte < bytesConsumedInPage) {
7347 drflac_uint8 segmentSize = oggbs->currentPageHeader.segmentTable[iSeg];
7348 if (iByte + segmentSize > bytesConsumedInPage) {
7349 break;
7350 } else {
7351 iSeg += 1;
7352 iByte += segmentSize;
7353 }
7354 }
7355
7356 *pBytesRemainingInSeg = oggbs->currentPageHeader.segmentTable[iSeg] - (drflac_uint8)(bytesConsumedInPage - iByte);
7357 return iSeg;
7358}
7359
7360static drflac_bool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs)
7361{
7362 /* 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. */
7363 for (;;) {
7364 drflac_bool32 atEndOfPage = DRFLAC_FALSE;
7365
7366 drflac_uint8 bytesRemainingInSeg;
7367 drflac_uint8 iFirstSeg = drflac_oggbs__get_current_segment_index(oggbs, &bytesRemainingInSeg);
7368
7369 drflac_uint32 bytesToEndOfPacketOrPage = bytesRemainingInSeg;
7370 for (drflac_uint8 iSeg = iFirstSeg; iSeg < oggbs->currentPageHeader.segmentCount; ++iSeg) {
7371 drflac_uint8 segmentSize = oggbs->currentPageHeader.segmentTable[iSeg];
7372 if (segmentSize < 255) {
7373 if (iSeg == oggbs->currentPageHeader.segmentCount-1) {
7374 atEndOfPage = DRFLAC_TRUE;
7375 }
7376
7377 break;
7378 }
7379
7380 bytesToEndOfPacketOrPage += segmentSize;
7381 }
7382
7383 /*
7384 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
7385 want to load the next page and keep searching for the end of the packet.
7386 */
7387 drflac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, drflac_seek_origin_current);
7388 oggbs->bytesRemainingInPage -= bytesToEndOfPacketOrPage;
7389
7390 if (atEndOfPage) {
7391 /*
7392 We're potentially at the next packet, but we need to check the next page first to be sure because the packet may
7393 straddle pages.
7394 */
7395 if (!drflac_oggbs__goto_next_page(oggbs)) {
7396 return DRFLAC_FALSE;
7397 }
7398
7399 /* If it's a fresh packet it most likely means we're at the next packet. */
7400 if ((oggbs->currentPageHeader.headerType & 0x01) == 0) {
7401 return DRFLAC_TRUE;
7402 }
7403 } else {
7404 /* We're at the next packet. */
7405 return DRFLAC_TRUE;
7406 }
7407 }
7408}
7409
7410static drflac_bool32 drflac_oggbs__seek_to_next_frame(drflac_oggbs* oggbs)
7411{
7412 /* The bitstream should be sitting on the first byte just after the header of the frame. */
7413
7414 /* What we're actually doing here is seeking to the start of the next packet. */
7415 return drflac_oggbs__seek_to_next_packet(oggbs);
7416}
7417#endif
7418
7419static size_t drflac__on_read_ogg(void* pUserData, void* bufferOut, size_t bytesToRead)
7420{
7421 drflac_oggbs* oggbs = (drflac_oggbs*)pUserData;
7422 drflac_uint8* pRunningBufferOut = (drflac_uint8*)bufferOut;
7423 size_t bytesRead = 0;
7424
7425 DRFLAC_ASSERT(oggbs != NULL);
7426 DRFLAC_ASSERT(pRunningBufferOut != NULL);
7427
7428 /* Reading is done page-by-page. If we've run out of bytes in the page we need to move to the next one. */
7429 while (bytesRead < bytesToRead) {
7430 size_t bytesRemainingToRead = bytesToRead - bytesRead;
7431
7432 if (oggbs->bytesRemainingInPage >= bytesRemainingToRead) {
7433 DRFLAC_COPY_MEMORY(pRunningBufferOut, oggbs->pageData + (oggbs->pageDataSize - oggbs->bytesRemainingInPage), bytesRemainingToRead);
7434 bytesRead += bytesRemainingToRead;
7435 oggbs->bytesRemainingInPage -= (drflac_uint32)bytesRemainingToRead;
7436 break;
7437 }
7438
7439 /* If we get here it means some of the requested data is contained in the next pages. */
7440 if (oggbs->bytesRemainingInPage > 0) {
7441 DRFLAC_COPY_MEMORY(pRunningBufferOut, oggbs->pageData + (oggbs->pageDataSize - oggbs->bytesRemainingInPage), oggbs->bytesRemainingInPage);
7442 bytesRead += oggbs->bytesRemainingInPage;
7443 pRunningBufferOut += oggbs->bytesRemainingInPage;
7444 oggbs->bytesRemainingInPage = 0;
7445 }
7446
7447 DRFLAC_ASSERT(bytesRemainingToRead > 0);
7448 if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) {
7449 break; /* Failed to go to the next page. Might have simply hit the end of the stream. */
7450 }
7451 }
7452
7453 return bytesRead;
7454}
7455
7456static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_seek_origin origin)
7457{
7458 drflac_oggbs* oggbs = (drflac_oggbs*)pUserData;
7459 int bytesSeeked = 0;
7460
7461 DRFLAC_ASSERT(oggbs != NULL);
7462 DRFLAC_ASSERT(offset >= 0); /* <-- Never seek backwards. */
7463
7464 /* Seeking is always forward which makes things a lot simpler. */
7465 if (origin == drflac_seek_origin_start) {
7466 if (!drflac_oggbs__seek_physical(oggbs, (int)oggbs->firstBytePos, drflac_seek_origin_start)) {
7467 return DRFLAC_FALSE;
7468 }
7469
7470 if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_fail_on_crc_mismatch)) {
7471 return DRFLAC_FALSE;
7472 }
7473
7474 return drflac__on_seek_ogg(pUserData, offset, drflac_seek_origin_current);
7475 }
7476
7477 DRFLAC_ASSERT(origin == drflac_seek_origin_current);
7478
7479 while (bytesSeeked < offset) {
7480 int bytesRemainingToSeek = offset - bytesSeeked;
7481 DRFLAC_ASSERT(bytesRemainingToSeek >= 0);
7482
7483 if (oggbs->bytesRemainingInPage >= (size_t)bytesRemainingToSeek) {
7484 bytesSeeked += bytesRemainingToSeek;
7485 (void)bytesSeeked; /* <-- Silence a dead store warning emitted by Clang Static Analyzer. */
7486 oggbs->bytesRemainingInPage -= bytesRemainingToSeek;
7487 break;
7488 }
7489
7490 /* If we get here it means some of the requested data is contained in the next pages. */
7491 if (oggbs->bytesRemainingInPage > 0) {
7492 bytesSeeked += (int)oggbs->bytesRemainingInPage;
7493 oggbs->bytesRemainingInPage = 0;
7494 }
7495
7496 DRFLAC_ASSERT(bytesRemainingToSeek > 0);
7497 if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_fail_on_crc_mismatch)) {
7498 /* Failed to go to the next page. We either hit the end of the stream or had a CRC mismatch. */
7499 return DRFLAC_FALSE;
7500 }
7501 }
7502
7503 return DRFLAC_TRUE;
7504}
7505
7506
7507static drflac_bool32 drflac_ogg__seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex)
7508{
7509 drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs;
7510 drflac_uint64 originalBytePos;
7511 drflac_uint64 runningGranulePosition;
7512 drflac_uint64 runningFrameBytePos;
7513 drflac_uint64 runningPCMFrameCount;
7514
7515 DRFLAC_ASSERT(oggbs != NULL);
7516
7517 originalBytePos = oggbs->currentBytePos; /* For recovery. Points to the OggS identifier. */
7518
7519 /* First seek to the first frame. */
7520 if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes)) {
7521 return DRFLAC_FALSE;
7522 }
7523 oggbs->bytesRemainingInPage = 0;
7524
7525 runningGranulePosition = 0;
7526 for (;;) {
7527 if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) {
7528 drflac_oggbs__seek_physical(oggbs, originalBytePos, drflac_seek_origin_start);
7529 return DRFLAC_FALSE; /* Never did find that sample... */
7530 }
7531
7532 runningFrameBytePos = oggbs->currentBytePos - drflac_ogg__get_page_header_size(&oggbs->currentPageHeader) - oggbs->pageDataSize;
7533 if (oggbs->currentPageHeader.granulePosition >= pcmFrameIndex) {
7534 break; /* The sample is somewhere in the previous page. */
7535 }
7536
7537 /*
7538 At this point we know the sample is not in the previous page. It could possibly be in this page. For simplicity we
7539 disregard any pages that do not begin a fresh packet.
7540 */
7541 if ((oggbs->currentPageHeader.headerType & 0x01) == 0) { /* <-- Is it a fresh page? */
7542 if (oggbs->currentPageHeader.segmentTable[0] >= 2) {
7543 drflac_uint8 firstBytesInPage[2];
7544 firstBytesInPage[0] = oggbs->pageData[0];
7545 firstBytesInPage[1] = oggbs->pageData[1];
7546
7547 if ((firstBytesInPage[0] == 0xFF) && (firstBytesInPage[1] & 0xFC) == 0xF8) { /* <-- Does the page begin with a frame's sync code? */
7548 runningGranulePosition = oggbs->currentPageHeader.granulePosition;
7549 }
7550
7551 continue;
7552 }
7553 }
7554 }
7555
7556 /*
7557 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
7558 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
7559 a new frame. This property means that after we've seeked to the page we can immediately start looping over frames until
7560 we find the one containing the target sample.
7561 */
7562 if (!drflac_oggbs__seek_physical(oggbs, runningFrameBytePos, drflac_seek_origin_start)) {
7563 return DRFLAC_FALSE;
7564 }
7565 if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) {
7566 return DRFLAC_FALSE;
7567 }
7568
7569 /*
7570 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
7571 looping over these frames until we find the one containing the sample we're after.
7572 */
7573 runningPCMFrameCount = runningGranulePosition;
7574 for (;;) {
7575 /*
7576 There are two ways to find the sample and seek past irrelevant frames:
7577 1) Use the native FLAC decoder.
7578 2) Use Ogg's framing system.
7579
7580 Both of these options have their own pros and cons. Using the native FLAC decoder is slower because it needs to
7581 do a full decode of the frame. Using Ogg's framing system is faster, but more complicated and involves some code
7582 duplication for the decoding of frame headers.
7583
7584 Another thing to consider is that using the Ogg framing system will perform direct seeking of the physical Ogg
7585 bitstream. This is important to consider because it means we cannot read data from the drflac_bs object using the
7586 standard drflac__*() APIs because that will read in extra data for its own internal caching which in turn breaks
7587 the positioning of the read pointer of the physical Ogg bitstream. Therefore, anything that would normally be read
7588 using the native FLAC decoding APIs, such as drflac__read_next_flac_frame_header(), need to be re-implemented so as to
7589 avoid the use of the drflac_bs object.
7590
7591 Considering these issues, I have decided to use the slower native FLAC decoding method for the following reasons:
7592 1) Seeking is already partially accelerated using Ogg's paging system in the code block above.
7593 2) Seeking in an Ogg encapsulated FLAC stream is probably quite uncommon.
7594 3) Simplicity.
7595 */
7596 drflac_uint64 firstPCMFrameInFLACFrame = 0;
7597 drflac_uint64 lastPCMFrameInFLACFrame = 0;
7598 drflac_uint64 pcmFrameCountInThisFrame;
7599
7600 if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
7601 return DRFLAC_FALSE;
7602 }
7603
7604 drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame);
7605
7606 pcmFrameCountInThisFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1;
7607
7608 /* If we are seeking to the end of the file and we've just hit it, we're done. */
7609 if (pcmFrameIndex == pFlac->totalPCMFrameCount && (runningPCMFrameCount + pcmFrameCountInThisFrame) == pFlac->totalPCMFrameCount) {
7610 drflac_result result = drflac__decode_flac_frame(pFlac);
7611 if (result == DRFLAC_SUCCESS) {
7612 pFlac->currentPCMFrame = pcmFrameIndex;
7613 pFlac->currentFLACFrame.pcmFramesRemaining = 0;
7614 return DRFLAC_TRUE;
7615 } else {
7616 return DRFLAC_FALSE;
7617 }
7618 }
7619
7620 if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFrame)) {
7621 /*
7622 The sample should be in this FLAC frame. We need to fully decode it, however if it's an invalid frame (a CRC mismatch), we need to pretend
7623 it never existed and keep iterating.
7624 */
7625 drflac_result result = drflac__decode_flac_frame(pFlac);
7626 if (result == DRFLAC_SUCCESS) {
7627 /* The frame is valid. We just need to skip over some samples to ensure it's sample-exact. */
7628 drflac_uint64 pcmFramesToDecode = (size_t)(pcmFrameIndex - runningPCMFrameCount); /* <-- Safe cast because the maximum number of samples in a frame is 65535. */
7629 if (pcmFramesToDecode == 0) {
7630 return DRFLAC_TRUE;
7631 }
7632
7633 pFlac->currentPCMFrame = runningPCMFrameCount;
7634
7635 return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; /* <-- If this fails, something bad has happened (it should never fail). */
7636 } else {
7637 if (result == DRFLAC_CRC_MISMATCH) {
7638 continue; /* CRC mismatch. Pretend this frame never existed. */
7639 } else {
7640 return DRFLAC_FALSE;
7641 }
7642 }
7643 } else {
7644 /*
7645 It's not in this frame. We need to seek past the frame, but check if there was a CRC mismatch. If so, we pretend this
7646 frame never existed and leave the running sample count untouched.
7647 */
7648 drflac_result result = drflac__seek_to_next_flac_frame(pFlac);
7649 if (result == DRFLAC_SUCCESS) {
7650 runningPCMFrameCount += pcmFrameCountInThisFrame;
7651 } else {
7652 if (result == DRFLAC_CRC_MISMATCH) {
7653 continue; /* CRC mismatch. Pretend this frame never existed. */
7654 } else {
7655 return DRFLAC_FALSE;
7656 }
7657 }
7658 }
7659 }
7660}
7661
7662
7663
7664static drflac_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_bool32 relaxed)
7665{
7666 drflac_ogg_page_header header;
7667 drflac_uint32 crc32 = DRFLAC_OGG_CAPTURE_PATTERN_CRC32;
7668 drflac_uint32 bytesRead = 0;
7669
7670 /* Pre Condition: The bit stream should be sitting just past the 4-byte OggS capture pattern. */
7671 (void)relaxed;
7672
7673 pInit->container = drflac_container_ogg;
7674 pInit->oggFirstBytePos = 0;
7675
7676 /*
7677 We'll get here if the first 4 bytes of the stream were the OggS capture pattern, however it doesn't necessarily mean the
7678 stream includes FLAC encoded audio. To check for this we need to scan the beginning-of-stream page markers and check if
7679 any match the FLAC specification. Important to keep in mind that the stream may be multiplexed.
7680 */
7681 if (drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) {
7682 return DRFLAC_FALSE;
7683 }
7684 pInit->runningFilePos += bytesRead;
7685
7686 for (;;) {
7687 int pageBodySize;
7688
7689 /* Break if we're past the beginning of stream page. */
7690 if ((header.headerType & 0x02) == 0) {
7691 return DRFLAC_FALSE;
7692 }
7693
7694 /* Check if it's a FLAC header. */
7695 pageBodySize = drflac_ogg__get_page_body_size(&header);
7696 if (pageBodySize == 51) { /* 51 = the lacing value of the FLAC header packet. */
7697 /* It could be a FLAC page... */
7698 drflac_uint32 bytesRemainingInPage = pageBodySize;
7699 drflac_uint8 packetType;
7700
7701 if (onRead(pUserData, &packetType, 1) != 1) {
7702 return DRFLAC_FALSE;
7703 }
7704
7705 bytesRemainingInPage -= 1;
7706 if (packetType == 0x7F) {
7707 /* Increasingly more likely to be a FLAC page... */
7708 drflac_uint8 sig[4];
7709 if (onRead(pUserData, sig, 4) != 4) {
7710 return DRFLAC_FALSE;
7711 }
7712
7713 bytesRemainingInPage -= 4;
7714 if (sig[0] == 'F' && sig[1] == 'L' && sig[2] == 'A' && sig[3] == 'C') {
7715 /* Almost certainly a FLAC page... */
7716 drflac_uint8 mappingVersion[2];
7717 if (onRead(pUserData, mappingVersion, 2) != 2) {
7718 return DRFLAC_FALSE;
7719 }
7720
7721 if (mappingVersion[0] != 1) {
7722 return DRFLAC_FALSE; /* Only supporting version 1.x of the Ogg mapping. */
7723 }
7724
7725 /*
7726 The next 2 bytes are the non-audio packets, not including this one. We don't care about this because we're going to
7727 be handling it in a generic way based on the serial number and packet types.
7728 */
7729 if (!onSeek(pUserData, 2, drflac_seek_origin_current)) {
7730 return DRFLAC_FALSE;
7731 }
7732
7733 /* Expecting the native FLAC signature "fLaC". */
7734 if (onRead(pUserData, sig, 4) != 4) {
7735 return DRFLAC_FALSE;
7736 }
7737
7738 if (sig[0] == 'f' && sig[1] == 'L' && sig[2] == 'a' && sig[3] == 'C') {
7739 /* The remaining data in the page should be the STREAMINFO block. */
7740 drflac_streaminfo streaminfo;
7741 drflac_uint8 isLastBlock;
7742 drflac_uint8 blockType;
7743 drflac_uint32 blockSize;
7744 if (!drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize)) {
7745 return DRFLAC_FALSE;
7746 }
7747
7748 if (blockType != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) {
7749 return DRFLAC_FALSE; /* Invalid block type. First block must be the STREAMINFO block. */
7750 }
7751
7752 if (drflac__read_streaminfo(onRead, pUserData, &streaminfo)) {
7753 /* Success! */
7754 pInit->hasStreamInfoBlock = DRFLAC_TRUE;
7755 pInit->sampleRate = streaminfo.sampleRate;
7756 pInit->channels = streaminfo.channels;
7757 pInit->bitsPerSample = streaminfo.bitsPerSample;
7758 pInit->totalPCMFrameCount = streaminfo.totalPCMFrameCount;
7759 pInit->maxBlockSizeInPCMFrames = streaminfo.maxBlockSizeInPCMFrames;
7760 pInit->hasMetadataBlocks = !isLastBlock;
7761
7762 if (onMeta) {
7763 drflac_metadata metadata;
7764 metadata.type = DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO;
7765 metadata.pRawData = NULL;
7766 metadata.rawDataSize = 0;
7767 metadata.data.streaminfo = streaminfo;
7768 onMeta(pUserDataMD, &metadata);
7769 }
7770
7771 pInit->runningFilePos += pageBodySize;
7772 pInit->oggFirstBytePos = pInit->runningFilePos - 79; /* Subtracting 79 will place us right on top of the "OggS" identifier of the FLAC bos page. */
7773 pInit->oggSerial = header.serialNumber;
7774 pInit->oggBosHeader = header;
7775 break;
7776 } else {
7777 /* Failed to read STREAMINFO block. Aww, so close... */
7778 return DRFLAC_FALSE;
7779 }
7780 } else {
7781 /* Invalid file. */
7782 return DRFLAC_FALSE;
7783 }
7784 } else {
7785 /* Not a FLAC header. Skip it. */
7786 if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) {
7787 return DRFLAC_FALSE;
7788 }
7789 }
7790 } else {
7791 /* Not a FLAC header. Seek past the entire page and move on to the next. */
7792 if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) {
7793 return DRFLAC_FALSE;
7794 }
7795 }
7796 } else {
7797 if (!onSeek(pUserData, pageBodySize, drflac_seek_origin_current)) {
7798 return DRFLAC_FALSE;
7799 }
7800 }
7801
7802 pInit->runningFilePos += pageBodySize;
7803
7804
7805 /* Read the header of the next page. */
7806 if (drflac_ogg__read_page_header(onRead, pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) {
7807 return DRFLAC_FALSE;
7808 }
7809 pInit->runningFilePos += bytesRead;
7810 }
7811
7812 /*
7813 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
7814 packets in the FLAC logical stream contain the metadata. The only thing left to do in the initialization phase for Ogg is to create the
7815 Ogg bistream object.
7816 */
7817 pInit->hasMetadataBlocks = DRFLAC_TRUE; /* <-- Always have at least VORBIS_COMMENT metadata block. */
7818 return DRFLAC_TRUE;
7819}
7820#endif
7821
7822static drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD)
7823{
7824 drflac_bool32 relaxed;
7825 drflac_uint8 id[4];
7826
7827 if (pInit == NULL || onRead == NULL || onSeek == NULL) {
7828 return DRFLAC_FALSE;
7829 }
7830
7831 DRFLAC_ZERO_MEMORY(pInit, sizeof(*pInit));
7832 pInit->onRead = onRead;
7833 pInit->onSeek = onSeek;
7834 pInit->onMeta = onMeta;
7835 pInit->container = container;
7836 pInit->pUserData = pUserData;
7837 pInit->pUserDataMD = pUserDataMD;
7838
7839 pInit->bs.onRead = onRead;
7840 pInit->bs.onSeek = onSeek;
7841 pInit->bs.pUserData = pUserData;
7842 drflac__reset_cache(&pInit->bs);
7843
7844
7845 /* If the container is explicitly defined then we can try opening in relaxed mode. */
7846 relaxed = container != drflac_container_unknown;
7847
7848 /* Skip over any ID3 tags. */
7849 for (;;) {
7850 if (onRead(pUserData, id, 4) != 4) {
7851 return DRFLAC_FALSE; /* Ran out of data. */
7852 }
7853 pInit->runningFilePos += 4;
7854
7855 if (id[0] == 'I' && id[1] == 'D' && id[2] == '3') {
7856 drflac_uint8 header[6];
7857 drflac_uint8 flags;
7858 drflac_uint32 headerSize;
7859
7860 if (onRead(pUserData, header, 6) != 6) {
7861 return DRFLAC_FALSE; /* Ran out of data. */
7862 }
7863 pInit->runningFilePos += 6;
7864
7865 flags = header[1];
7866
7867 DRFLAC_COPY_MEMORY(&headerSize, header+2, 4);
7868 headerSize = drflac__unsynchsafe_32(drflac__be2host_32(headerSize));
7869 if (flags & 0x10) {
7870 headerSize += 10;
7871 }
7872
7873 if (!onSeek(pUserData, headerSize, drflac_seek_origin_current)) {
7874 return DRFLAC_FALSE; /* Failed to seek past the tag. */
7875 }
7876 pInit->runningFilePos += headerSize;
7877 } else {
7878 break;
7879 }
7880 }
7881
7882 if (id[0] == 'f' && id[1] == 'L' && id[2] == 'a' && id[3] == 'C') {
7883 return drflac__init_private__native(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed);
7884 }
7885#ifndef DR_FLAC_NO_OGG
7886 if (id[0] == 'O' && id[1] == 'g' && id[2] == 'g' && id[3] == 'S') {
7887 return drflac__init_private__ogg(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed);
7888 }
7889#endif
7890
7891 /* If we get here it means we likely don't have a header. Try opening in relaxed mode, if applicable. */
7892 if (relaxed) {
7893 if (container == drflac_container_native) {
7894 return drflac__init_private__native(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed);
7895 }
7896#ifndef DR_FLAC_NO_OGG
7897 if (container == drflac_container_ogg) {
7898 return drflac__init_private__ogg(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed);
7899 }
7900#endif
7901 }
7902
7903 /* Unsupported container. */
7904 return DRFLAC_FALSE;
7905}
7906
7907static void drflac__init_from_info(drflac* pFlac, const drflac_init_info* pInit)
7908{
7909 DRFLAC_ASSERT(pFlac != NULL);
7910 DRFLAC_ASSERT(pInit != NULL);
7911
7912 DRFLAC_ZERO_MEMORY(pFlac, sizeof(*pFlac));
7913 pFlac->bs = pInit->bs;
7914 pFlac->onMeta = pInit->onMeta;
7915 pFlac->pUserDataMD = pInit->pUserDataMD;
7916 pFlac->maxBlockSizeInPCMFrames = pInit->maxBlockSizeInPCMFrames;
7917 pFlac->sampleRate = pInit->sampleRate;
7918 pFlac->channels = (drflac_uint8)pInit->channels;
7919 pFlac->bitsPerSample = (drflac_uint8)pInit->bitsPerSample;
7920 pFlac->totalPCMFrameCount = pInit->totalPCMFrameCount;
7921 pFlac->container = pInit->container;
7922}
7923
7924
7925static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD, const drflac_allocation_callbacks* pAllocationCallbacks)
7926{
7927 drflac_init_info init;
7928 drflac_uint32 allocationSize;
7929 drflac_uint32 wholeSIMDVectorCountPerChannel;
7930 drflac_uint32 decodedSamplesAllocationSize;
7931#ifndef DR_FLAC_NO_OGG
7932 drflac_oggbs* pOggbs = NULL;
7933#endif
7934 drflac_uint64 firstFramePos;
7935 drflac_uint64 seektablePos;
7936 drflac_uint32 seekpointCount;
7937 drflac_allocation_callbacks allocationCallbacks;
7938 drflac* pFlac;
7939
7940 /* CPU support first. */
7941 drflac__init_cpu_caps();
7942
7943 if (!drflac__init_private(&init, onRead, onSeek, onMeta, container, pUserData, pUserDataMD)) {
7944 return NULL;
7945 }
7946
7947 if (pAllocationCallbacks != NULL) {
7948 allocationCallbacks = *pAllocationCallbacks;
7949 if (allocationCallbacks.onFree == NULL || (allocationCallbacks.onMalloc == NULL && allocationCallbacks.onRealloc == NULL)) {
7950 return NULL; /* Invalid allocation callbacks. */
7951 }
7952 } else {
7953 allocationCallbacks.pUserData = NULL;
7954 allocationCallbacks.onMalloc = drflac__malloc_default;
7955 allocationCallbacks.onRealloc = drflac__realloc_default;
7956 allocationCallbacks.onFree = drflac__free_default;
7957 }
7958
7959
7960 /*
7961 The size of the allocation for the drflac object needs to be large enough to fit the following:
7962 1) The main members of the drflac structure
7963 2) A block of memory large enough to store the decoded samples of the largest frame in the stream
7964 3) If the container is Ogg, a drflac_oggbs object
7965
7966 The complicated part of the allocation is making sure there's enough room the decoded samples, taking into consideration
7967 the different SIMD instruction sets.
7968 */
7969 allocationSize = sizeof(drflac);
7970
7971 /*
7972 The allocation size for decoded frames depends on the number of 32-bit integers that fit inside the largest SIMD vector
7973 we are supporting.
7974 */
7975 if ((init.maxBlockSizeInPCMFrames % (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))) == 0) {
7976 wholeSIMDVectorCountPerChannel = (init.maxBlockSizeInPCMFrames / (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32)));
7977 } else {
7978 wholeSIMDVectorCountPerChannel = (init.maxBlockSizeInPCMFrames / (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))) + 1;
7979 }
7980
7981 decodedSamplesAllocationSize = wholeSIMDVectorCountPerChannel * DRFLAC_MAX_SIMD_VECTOR_SIZE * init.channels;
7982
7983 allocationSize += decodedSamplesAllocationSize;
7984 allocationSize += DRFLAC_MAX_SIMD_VECTOR_SIZE; /* Allocate extra bytes to ensure we have enough for alignment. */
7985
7986#ifndef DR_FLAC_NO_OGG
7987 /* There's additional data required for Ogg streams. */
7988 if (init.container == drflac_container_ogg) {
7989 allocationSize += sizeof(drflac_oggbs);
7990
7991 pOggbs = (drflac_oggbs*)drflac__malloc_from_callbacks(sizeof(*pOggbs), &allocationCallbacks);
7992 if (pOggbs == NULL) {
7993 return NULL; /*DRFLAC_OUT_OF_MEMORY;*/
7994 }
7995
7996 DRFLAC_ZERO_MEMORY(pOggbs, sizeof(*pOggbs));
7997 pOggbs->onRead = onRead;
7998 pOggbs->onSeek = onSeek;
7999 pOggbs->pUserData = pUserData;
8000 pOggbs->currentBytePos = init.oggFirstBytePos;
8001 pOggbs->firstBytePos = init.oggFirstBytePos;
8002 pOggbs->serialNumber = init.oggSerial;
8003 pOggbs->bosPageHeader = init.oggBosHeader;
8004 pOggbs->bytesRemainingInPage = 0;
8005 }
8006#endif
8007
8008 /*
8009 This part is a bit awkward. We need to load the seektable so that it can be referenced in-memory, but I want the drflac object to
8010 consist of only a single heap allocation. To this, the size of the seek table needs to be known, which we determine when reading
8011 and decoding the metadata.
8012 */
8013 firstFramePos = 42; /* <-- We know we are at byte 42 at this point. */
8014 seektablePos = 0;
8015 seekpointCount = 0;
8016 if (init.hasMetadataBlocks) {
8017 drflac_read_proc onReadOverride = onRead;
8018 drflac_seek_proc onSeekOverride = onSeek;
8019 void* pUserDataOverride = pUserData;
8020
8021#ifndef DR_FLAC_NO_OGG
8022 if (init.container == drflac_container_ogg) {
8023 onReadOverride = drflac__on_read_ogg;
8024 onSeekOverride = drflac__on_seek_ogg;
8025 pUserDataOverride = (void*)pOggbs;
8026 }
8027#endif
8028
8029 if (!drflac__read_and_decode_metadata(onReadOverride, onSeekOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seekpointCount, &allocationCallbacks)) {
8030 #ifndef DR_FLAC_NO_OGG
8031 drflac__free_from_callbacks(pOggbs, &allocationCallbacks);
8032 #endif
8033 return NULL;
8034 }
8035
8036 allocationSize += seekpointCount * sizeof(drflac_seekpoint);
8037 }
8038
8039
8040 pFlac = (drflac*)drflac__malloc_from_callbacks(allocationSize, &allocationCallbacks);
8041 if (pFlac == NULL) {
8042 #ifndef DR_FLAC_NO_OGG
8043 drflac__free_from_callbacks(pOggbs, &allocationCallbacks);
8044 #endif
8045 return NULL;
8046 }
8047
8048 drflac__init_from_info(pFlac, &init);
8049 pFlac->allocationCallbacks = allocationCallbacks;
8050 pFlac->pDecodedSamples = (drflac_int32*)drflac_align((size_t)pFlac->pExtraData, DRFLAC_MAX_SIMD_VECTOR_SIZE);
8051
8052#ifndef DR_FLAC_NO_OGG
8053 if (init.container == drflac_container_ogg) {
8054 drflac_oggbs* pInternalOggbs = (drflac_oggbs*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize + (seekpointCount * sizeof(drflac_seekpoint)));
8055 DRFLAC_COPY_MEMORY(pInternalOggbs, pOggbs, sizeof(*pOggbs));
8056
8057 /* At this point the pOggbs object has been handed over to pInternalOggbs and can be freed. */
8058 drflac__free_from_callbacks(pOggbs, &allocationCallbacks);
8059 pOggbs = NULL;
8060
8061 /* The Ogg bistream needs to be layered on top of the original bitstream. */
8062 pFlac->bs.onRead = drflac__on_read_ogg;
8063 pFlac->bs.onSeek = drflac__on_seek_ogg;
8064 pFlac->bs.pUserData = (void*)pInternalOggbs;
8065 pFlac->_oggbs = (void*)pInternalOggbs;
8066 }
8067#endif
8068
8069 pFlac->firstFLACFramePosInBytes = firstFramePos;
8070
8071 /* NOTE: Seektables are not currently compatible with Ogg encapsulation (Ogg has its own accelerated seeking system). I may change this later, so I'm leaving this here for now. */
8072#ifndef DR_FLAC_NO_OGG
8073 if (init.container == drflac_container_ogg)
8074 {
8075 pFlac->pSeekpoints = NULL;
8076 pFlac->seekpointCount = 0;
8077 }
8078 else
8079#endif
8080 {
8081 /* If we have a seektable we need to load it now, making sure we move back to where we were previously. */
8082 if (seektablePos != 0) {
8083 pFlac->seekpointCount = seekpointCount;
8084 pFlac->pSeekpoints = (drflac_seekpoint*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize);
8085
8086 DRFLAC_ASSERT(pFlac->bs.onSeek != NULL);
8087 DRFLAC_ASSERT(pFlac->bs.onRead != NULL);
8088
8089 /* Seek to the seektable, then just read directly into our seektable buffer. */
8090 if (pFlac->bs.onSeek(pFlac->bs.pUserData, (int)seektablePos, drflac_seek_origin_start)) {
8091 drflac_uint32 iSeekpoint;
8092
8093 for (iSeekpoint = 0; iSeekpoint < seekpointCount; iSeekpoint += 1) {
8094 if (pFlac->bs.onRead(pFlac->bs.pUserData, pFlac->pSeekpoints + iSeekpoint, DRFLAC_SEEKPOINT_SIZE_IN_BYTES) == DRFLAC_SEEKPOINT_SIZE_IN_BYTES) {
8095 /* Endian swap. */
8096 pFlac->pSeekpoints[iSeekpoint].firstPCMFrame = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].firstPCMFrame);
8097 pFlac->pSeekpoints[iSeekpoint].flacFrameOffset = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].flacFrameOffset);
8098 pFlac->pSeekpoints[iSeekpoint].pcmFrameCount = drflac__be2host_16(pFlac->pSeekpoints[iSeekpoint].pcmFrameCount);
8099 } else {
8100 /* Failed to read the seektable. Pretend we don't have one. */
8101 pFlac->pSeekpoints = NULL;
8102 pFlac->seekpointCount = 0;
8103 break;
8104 }
8105 }
8106
8107 /* We need to seek back to where we were. If this fails it's a critical error. */
8108 if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, drflac_seek_origin_start)) {
8109 drflac__free_from_callbacks(pFlac, &allocationCallbacks);
8110 return NULL;
8111 }
8112 } else {
8113 /* Failed to seek to the seektable. Ominous sign, but for now we can just pretend we don't have one. */
8114 pFlac->pSeekpoints = NULL;
8115 pFlac->seekpointCount = 0;
8116 }
8117 }
8118 }
8119
8120
8121 /*
8122 If we get here, but don't have a STREAMINFO block, it means we've opened the stream in relaxed mode and need to decode
8123 the first frame.
8124 */
8125 if (!init.hasStreamInfoBlock) {
8126 pFlac->currentFLACFrame.header = init.firstFrameHeader;
8127 for (;;) {
8128 drflac_result result = drflac__decode_flac_frame(pFlac);
8129 if (result == DRFLAC_SUCCESS) {
8130 break;
8131 } else {
8132 if (result == DRFLAC_CRC_MISMATCH) {
8133 if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
8134 drflac__free_from_callbacks(pFlac, &allocationCallbacks);
8135 return NULL;
8136 }
8137 continue;
8138 } else {
8139 drflac__free_from_callbacks(pFlac, &allocationCallbacks);
8140 return NULL;
8141 }
8142 }
8143 }
8144 }
8145
8146 return pFlac;
8147}
8148
8149
8150
8151#ifndef DR_FLAC_NO_STDIO
8152#include <stdio.h>
8153#ifndef DR_FLAC_NO_WCHAR
8154#include <wchar.h> /* For wcslen(), wcsrtombs() */
8155#endif
8156
8157/* Errno */
8158/* drflac_result_from_errno() is only used for fopen() and wfopen() so putting it inside DR_WAV_NO_STDIO for now. If something else needs this later we can move it out. */
8159#include <errno.h>
8160static drflac_result drflac_result_from_errno(int e)
8161{
8162 switch (e)
8163 {
8164 case 0: return DRFLAC_SUCCESS;
8165 #ifdef EPERM
8166 case EPERM: return DRFLAC_INVALID_OPERATION;
8167 #endif
8168 #ifdef ENOENT
8169 case ENOENT: return DRFLAC_DOES_NOT_EXIST;
8170 #endif
8171 #ifdef ESRCH
8172 case ESRCH: return DRFLAC_DOES_NOT_EXIST;
8173 #endif
8174 #ifdef EINTR
8175 case EINTR: return DRFLAC_INTERRUPT;
8176 #endif
8177 #ifdef EIO
8178 case EIO: return DRFLAC_IO_ERROR;
8179 #endif
8180 #ifdef ENXIO
8181 case ENXIO: return DRFLAC_DOES_NOT_EXIST;
8182 #endif
8183 #ifdef E2BIG
8184 case E2BIG: return DRFLAC_INVALID_ARGS;
8185 #endif
8186 #ifdef ENOEXEC
8187 case ENOEXEC: return DRFLAC_INVALID_FILE;
8188 #endif
8189 #ifdef EBADF
8190 case EBADF: return DRFLAC_INVALID_FILE;
8191 #endif
8192 #ifdef ECHILD
8193 case ECHILD: return DRFLAC_ERROR;
8194 #endif
8195 #ifdef EAGAIN
8196 case EAGAIN: return DRFLAC_UNAVAILABLE;
8197 #endif
8198 #ifdef ENOMEM
8199 case ENOMEM: return DRFLAC_OUT_OF_MEMORY;
8200 #endif
8201 #ifdef EACCES
8202 case EACCES: return DRFLAC_ACCESS_DENIED;
8203 #endif
8204 #ifdef EFAULT
8205 case EFAULT: return DRFLAC_BAD_ADDRESS;
8206 #endif
8207 #ifdef ENOTBLK
8208 case ENOTBLK: return DRFLAC_ERROR;
8209 #endif
8210 #ifdef EBUSY
8211 case EBUSY: return DRFLAC_BUSY;
8212 #endif
8213 #ifdef EEXIST
8214 case EEXIST: return DRFLAC_ALREADY_EXISTS;
8215 #endif
8216 #ifdef EXDEV
8217 case EXDEV: return DRFLAC_ERROR;
8218 #endif
8219 #ifdef ENODEV
8220 case ENODEV: return DRFLAC_DOES_NOT_EXIST;
8221 #endif
8222 #ifdef ENOTDIR
8223 case ENOTDIR: return DRFLAC_NOT_DIRECTORY;
8224 #endif
8225 #ifdef EISDIR
8226 case EISDIR: return DRFLAC_IS_DIRECTORY;
8227 #endif
8228 #ifdef EINVAL
8229 case EINVAL: return DRFLAC_INVALID_ARGS;
8230 #endif
8231 #ifdef ENFILE
8232 case ENFILE: return DRFLAC_TOO_MANY_OPEN_FILES;
8233 #endif
8234 #ifdef EMFILE
8235 case EMFILE: return DRFLAC_TOO_MANY_OPEN_FILES;
8236 #endif
8237 #ifdef ENOTTY
8238 case ENOTTY: return DRFLAC_INVALID_OPERATION;
8239 #endif
8240 #ifdef ETXTBSY
8241 case ETXTBSY: return DRFLAC_BUSY;
8242 #endif
8243 #ifdef EFBIG
8244 case EFBIG: return DRFLAC_TOO_BIG;
8245 #endif
8246 #ifdef ENOSPC
8247 case ENOSPC: return DRFLAC_NO_SPACE;
8248 #endif
8249 #ifdef ESPIPE
8250 case ESPIPE: return DRFLAC_BAD_SEEK;
8251 #endif
8252 #ifdef EROFS
8253 case EROFS: return DRFLAC_ACCESS_DENIED;
8254 #endif
8255 #ifdef EMLINK
8256 case EMLINK: return DRFLAC_TOO_MANY_LINKS;
8257 #endif
8258 #ifdef EPIPE
8259 case EPIPE: return DRFLAC_BAD_PIPE;
8260 #endif
8261 #ifdef EDOM
8262 case EDOM: return DRFLAC_OUT_OF_RANGE;
8263 #endif
8264 #ifdef ERANGE
8265 case ERANGE: return DRFLAC_OUT_OF_RANGE;
8266 #endif
8267 #ifdef EDEADLK
8268 case EDEADLK: return DRFLAC_DEADLOCK;
8269 #endif
8270 #ifdef ENAMETOOLONG
8271 case ENAMETOOLONG: return DRFLAC_PATH_TOO_LONG;
8272 #endif
8273 #ifdef ENOLCK
8274 case ENOLCK: return DRFLAC_ERROR;
8275 #endif
8276 #ifdef ENOSYS
8277 case ENOSYS: return DRFLAC_NOT_IMPLEMENTED;
8278 #endif
8279 #ifdef ENOTEMPTY
8280 case ENOTEMPTY: return DRFLAC_DIRECTORY_NOT_EMPTY;
8281 #endif
8282 #ifdef ELOOP
8283 case ELOOP: return DRFLAC_TOO_MANY_LINKS;
8284 #endif
8285 #ifdef ENOMSG
8286 case ENOMSG: return DRFLAC_NO_MESSAGE;
8287 #endif
8288 #ifdef EIDRM
8289 case EIDRM: return DRFLAC_ERROR;
8290 #endif
8291 #ifdef ECHRNG
8292 case ECHRNG: return DRFLAC_ERROR;
8293 #endif
8294 #ifdef EL2NSYNC
8295 case EL2NSYNC: return DRFLAC_ERROR;
8296 #endif
8297 #ifdef EL3HLT
8298 case EL3HLT: return DRFLAC_ERROR;
8299 #endif
8300 #ifdef EL3RST
8301 case EL3RST: return DRFLAC_ERROR;
8302 #endif
8303 #ifdef ELNRNG
8304 case ELNRNG: return DRFLAC_OUT_OF_RANGE;
8305 #endif
8306 #ifdef EUNATCH
8307 case EUNATCH: return DRFLAC_ERROR;
8308 #endif
8309 #ifdef ENOCSI
8310 case ENOCSI: return DRFLAC_ERROR;
8311 #endif
8312 #ifdef EL2HLT
8313 case EL2HLT: return DRFLAC_ERROR;
8314 #endif
8315 #ifdef EBADE
8316 case EBADE: return DRFLAC_ERROR;
8317 #endif
8318 #ifdef EBADR
8319 case EBADR: return DRFLAC_ERROR;
8320 #endif
8321 #ifdef EXFULL
8322 case EXFULL: return DRFLAC_ERROR;
8323 #endif
8324 #ifdef ENOANO
8325 case ENOANO: return DRFLAC_ERROR;
8326 #endif
8327 #ifdef EBADRQC
8328 case EBADRQC: return DRFLAC_ERROR;
8329 #endif
8330 #ifdef EBADSLT
8331 case EBADSLT: return DRFLAC_ERROR;
8332 #endif
8333 #ifdef EBFONT
8334 case EBFONT: return DRFLAC_INVALID_FILE;
8335 #endif
8336 #ifdef ENOSTR
8337 case ENOSTR: return DRFLAC_ERROR;
8338 #endif
8339 #ifdef ENODATA
8340 case ENODATA: return DRFLAC_NO_DATA_AVAILABLE;
8341 #endif
8342 #ifdef ETIME
8343 case ETIME: return DRFLAC_TIMEOUT;
8344 #endif
8345 #ifdef ENOSR
8346 case ENOSR: return DRFLAC_NO_DATA_AVAILABLE;
8347 #endif
8348 #ifdef ENONET
8349 case ENONET: return DRFLAC_NO_NETWORK;
8350 #endif
8351 #ifdef ENOPKG
8352 case ENOPKG: return DRFLAC_ERROR;
8353 #endif
8354 #ifdef EREMOTE
8355 case EREMOTE: return DRFLAC_ERROR;
8356 #endif
8357 #ifdef ENOLINK
8358 case ENOLINK: return DRFLAC_ERROR;
8359 #endif
8360 #ifdef EADV
8361 case EADV: return DRFLAC_ERROR;
8362 #endif
8363 #ifdef ESRMNT
8364 case ESRMNT: return DRFLAC_ERROR;
8365 #endif
8366 #ifdef ECOMM
8367 case ECOMM: return DRFLAC_ERROR;
8368 #endif
8369 #ifdef EPROTO
8370 case EPROTO: return DRFLAC_ERROR;
8371 #endif
8372 #ifdef EMULTIHOP
8373 case EMULTIHOP: return DRFLAC_ERROR;
8374 #endif
8375 #ifdef EDOTDOT
8376 case EDOTDOT: return DRFLAC_ERROR;
8377 #endif
8378 #ifdef EBADMSG
8379 case EBADMSG: return DRFLAC_BAD_MESSAGE;
8380 #endif
8381 #ifdef EOVERFLOW
8382 case EOVERFLOW: return DRFLAC_TOO_BIG;
8383 #endif
8384 #ifdef ENOTUNIQ
8385 case ENOTUNIQ: return DRFLAC_NOT_UNIQUE;
8386 #endif
8387 #ifdef EBADFD
8388 case EBADFD: return DRFLAC_ERROR;
8389 #endif
8390 #ifdef EREMCHG
8391 case EREMCHG: return DRFLAC_ERROR;
8392 #endif
8393 #ifdef ELIBACC
8394 case ELIBACC: return DRFLAC_ACCESS_DENIED;
8395 #endif
8396 #ifdef ELIBBAD
8397 case ELIBBAD: return DRFLAC_INVALID_FILE;
8398 #endif
8399 #ifdef ELIBSCN
8400 case ELIBSCN: return DRFLAC_INVALID_FILE;
8401 #endif
8402 #ifdef ELIBMAX
8403 case ELIBMAX: return DRFLAC_ERROR;
8404 #endif
8405 #ifdef ELIBEXEC
8406 case ELIBEXEC: return DRFLAC_ERROR;
8407 #endif
8408 #ifdef EILSEQ
8409 case EILSEQ: return DRFLAC_INVALID_DATA;
8410 #endif
8411 #ifdef ERESTART
8412 case ERESTART: return DRFLAC_ERROR;
8413 #endif
8414 #ifdef ESTRPIPE
8415 case ESTRPIPE: return DRFLAC_ERROR;
8416 #endif
8417 #ifdef EUSERS
8418 case EUSERS: return DRFLAC_ERROR;
8419 #endif
8420 #ifdef ENOTSOCK
8421 case ENOTSOCK: return DRFLAC_NOT_SOCKET;
8422 #endif
8423 #ifdef EDESTADDRREQ
8424 case EDESTADDRREQ: return DRFLAC_NO_ADDRESS;
8425 #endif
8426 #ifdef EMSGSIZE
8427 case EMSGSIZE: return DRFLAC_TOO_BIG;
8428 #endif
8429 #ifdef EPROTOTYPE
8430 case EPROTOTYPE: return DRFLAC_BAD_PROTOCOL;
8431 #endif
8432 #ifdef ENOPROTOOPT
8433 case ENOPROTOOPT: return DRFLAC_PROTOCOL_UNAVAILABLE;
8434 #endif
8435 #ifdef EPROTONOSUPPORT
8436 case EPROTONOSUPPORT: return DRFLAC_PROTOCOL_NOT_SUPPORTED;
8437 #endif
8438 #ifdef ESOCKTNOSUPPORT
8439 case ESOCKTNOSUPPORT: return DRFLAC_SOCKET_NOT_SUPPORTED;
8440 #endif
8441 #ifdef EOPNOTSUPP
8442 case EOPNOTSUPP: return DRFLAC_INVALID_OPERATION;
8443 #endif
8444 #ifdef EPFNOSUPPORT
8445 case EPFNOSUPPORT: return DRFLAC_PROTOCOL_FAMILY_NOT_SUPPORTED;
8446 #endif
8447 #ifdef EAFNOSUPPORT
8448 case EAFNOSUPPORT: return DRFLAC_ADDRESS_FAMILY_NOT_SUPPORTED;
8449 #endif
8450 #ifdef EADDRINUSE
8451 case EADDRINUSE: return DRFLAC_ALREADY_IN_USE;
8452 #endif
8453 #ifdef EADDRNOTAVAIL
8454 case EADDRNOTAVAIL: return DRFLAC_ERROR;
8455 #endif
8456 #ifdef ENETDOWN
8457 case ENETDOWN: return DRFLAC_NO_NETWORK;
8458 #endif
8459 #ifdef ENETUNREACH
8460 case ENETUNREACH: return DRFLAC_NO_NETWORK;
8461 #endif
8462 #ifdef ENETRESET
8463 case ENETRESET: return DRFLAC_NO_NETWORK;
8464 #endif
8465 #ifdef ECONNABORTED
8466 case ECONNABORTED: return DRFLAC_NO_NETWORK;
8467 #endif
8468 #ifdef ECONNRESET
8469 case ECONNRESET: return DRFLAC_CONNECTION_RESET;
8470 #endif
8471 #ifdef ENOBUFS
8472 case ENOBUFS: return DRFLAC_NO_SPACE;
8473 #endif
8474 #ifdef EISCONN
8475 case EISCONN: return DRFLAC_ALREADY_CONNECTED;
8476 #endif
8477 #ifdef ENOTCONN
8478 case ENOTCONN: return DRFLAC_NOT_CONNECTED;
8479 #endif
8480 #ifdef ESHUTDOWN
8481 case ESHUTDOWN: return DRFLAC_ERROR;
8482 #endif
8483 #ifdef ETOOMANYREFS
8484 case ETOOMANYREFS: return DRFLAC_ERROR;
8485 #endif
8486 #ifdef ETIMEDOUT
8487 case ETIMEDOUT: return DRFLAC_TIMEOUT;
8488 #endif
8489 #ifdef ECONNREFUSED
8490 case ECONNREFUSED: return DRFLAC_CONNECTION_REFUSED;
8491 #endif
8492 #ifdef EHOSTDOWN
8493 case EHOSTDOWN: return DRFLAC_NO_HOST;
8494 #endif
8495 #ifdef EHOSTUNREACH
8496 case EHOSTUNREACH: return DRFLAC_NO_HOST;
8497 #endif
8498 #ifdef EALREADY
8499 case EALREADY: return DRFLAC_IN_PROGRESS;
8500 #endif
8501 #ifdef EINPROGRESS
8502 case EINPROGRESS: return DRFLAC_IN_PROGRESS;
8503 #endif
8504 #ifdef ESTALE
8505 case ESTALE: return DRFLAC_INVALID_FILE;
8506 #endif
8507 #ifdef EUCLEAN
8508 case EUCLEAN: return DRFLAC_ERROR;
8509 #endif
8510 #ifdef ENOTNAM
8511 case ENOTNAM: return DRFLAC_ERROR;
8512 #endif
8513 #ifdef ENAVAIL
8514 case ENAVAIL: return DRFLAC_ERROR;
8515 #endif
8516 #ifdef EISNAM
8517 case EISNAM: return DRFLAC_ERROR;
8518 #endif
8519 #ifdef EREMOTEIO
8520 case EREMOTEIO: return DRFLAC_IO_ERROR;
8521 #endif
8522 #ifdef EDQUOT
8523 case EDQUOT: return DRFLAC_NO_SPACE;
8524 #endif
8525 #ifdef ENOMEDIUM
8526 case ENOMEDIUM: return DRFLAC_DOES_NOT_EXIST;
8527 #endif
8528 #ifdef EMEDIUMTYPE
8529 case EMEDIUMTYPE: return DRFLAC_ERROR;
8530 #endif
8531 #ifdef ECANCELED
8532 case ECANCELED: return DRFLAC_CANCELLED;
8533 #endif
8534 #ifdef ENOKEY
8535 case ENOKEY: return DRFLAC_ERROR;
8536 #endif
8537 #ifdef EKEYEXPIRED
8538 case EKEYEXPIRED: return DRFLAC_ERROR;
8539 #endif
8540 #ifdef EKEYREVOKED
8541 case EKEYREVOKED: return DRFLAC_ERROR;
8542 #endif
8543 #ifdef EKEYREJECTED
8544 case EKEYREJECTED: return DRFLAC_ERROR;
8545 #endif
8546 #ifdef EOWNERDEAD
8547 case EOWNERDEAD: return DRFLAC_ERROR;
8548 #endif
8549 #ifdef ENOTRECOVERABLE
8550 case ENOTRECOVERABLE: return DRFLAC_ERROR;
8551 #endif
8552 #ifdef ERFKILL
8553 case ERFKILL: return DRFLAC_ERROR;
8554 #endif
8555 #ifdef EHWPOISON
8556 case EHWPOISON: return DRFLAC_ERROR;
8557 #endif
8558 default: return DRFLAC_ERROR;
8559 }
8560}
8561/* End Errno */
8562
8563/* fopen */
8564static drflac_result drflac_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
8565{
8566#if defined(_MSC_VER) && _MSC_VER >= 1400
8567 errno_t err;
8568#endif
8569
8570 if (ppFile != NULL) {
8571 *ppFile = NULL; /* Safety. */
8572 }
8573
8574 if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
8575 return DRFLAC_INVALID_ARGS;
8576 }
8577
8578#if defined(_MSC_VER) && _MSC_VER >= 1400
8579 err = fopen_s(ppFile, pFilePath, pOpenMode);
8580 if (err != 0) {
8581 return drflac_result_from_errno(err);
8582 }
8583#else
8584#if defined(_WIN32) || defined(__APPLE__)
8585 *ppFile = fopen(pFilePath, pOpenMode);
8586#else
8587 #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE)
8588 *ppFile = fopen64(pFilePath, pOpenMode);
8589 #else
8590 *ppFile = fopen(pFilePath, pOpenMode);
8591 #endif
8592#endif
8593 if (*ppFile == NULL) {
8594 drflac_result result = drflac_result_from_errno(errno);
8595 if (result == DRFLAC_SUCCESS) {
8596 result = DRFLAC_ERROR; /* Just a safety check to make sure we never ever return success when pFile == NULL. */
8597 }
8598
8599 return result;
8600 }
8601#endif
8602
8603 return DRFLAC_SUCCESS;
8604}
8605
8606/*
8607_wfopen() isn't always available in all compilation environments.
8608
8609 * Windows only.
8610 * MSVC seems to support it universally as far back as VC6 from what I can tell (haven't checked further back).
8611 * MinGW-64 (both 32- and 64-bit) seems to support it.
8612 * MinGW wraps it in !defined(__STRICT_ANSI__).
8613 * OpenWatcom wraps it in !defined(_NO_EXT_KEYS).
8614
8615This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs()
8616fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support.
8617*/
8618#if defined(_WIN32)
8619 #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS))
8620 #define DRFLAC_HAS_WFOPEN
8621 #endif
8622#endif
8623
8624#ifndef DR_FLAC_NO_WCHAR
8625static drflac_result drflac_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drflac_allocation_callbacks* pAllocationCallbacks)
8626{
8627 if (ppFile != NULL) {
8628 *ppFile = NULL; /* Safety. */
8629 }
8630
8631 if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
8632 return DRFLAC_INVALID_ARGS;
8633 }
8634
8635#if defined(DRFLAC_HAS_WFOPEN)
8636 {
8637 /* Use _wfopen() on Windows. */
8638 #if defined(_MSC_VER) && _MSC_VER >= 1400
8639 errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode);
8640 if (err != 0) {
8641 return drflac_result_from_errno(err);
8642 }
8643 #else
8644 *ppFile = _wfopen(pFilePath, pOpenMode);
8645 if (*ppFile == NULL) {
8646 return drflac_result_from_errno(errno);
8647 }
8648 #endif
8649 (void)pAllocationCallbacks;
8650 }
8651#else
8652 /*
8653 Use fopen() on anything other than Windows. Requires a conversion. This is annoying because
8654 fopen() is locale specific. The only real way I can think of to do this is with wcsrtombs(). Note
8655 that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for
8656 maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler
8657 error I'll look into improving compatibility.
8658 */
8659
8660 /*
8661 Some compilers don't support wchar_t or wcsrtombs() which we're using below. In this case we just
8662 need to abort with an error. If you encounter a compiler lacking such support, add it to this list
8663 and submit a bug report and it'll be added to the library upstream.
8664 */
8665 #if defined(__DJGPP__)
8666 {
8667 /* Nothing to do here. This will fall through to the error check below. */
8668 }
8669 #else
8670 {
8671 mbstate_t mbs;
8672 size_t lenMB;
8673 const wchar_t* pFilePathTemp = pFilePath;
8674 char* pFilePathMB = NULL;
8675 char pOpenModeMB[32] = {0};
8676
8677 /* Get the length first. */
8678 DRFLAC_ZERO_OBJECT(&mbs);
8679 lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs);
8680 if (lenMB == (size_t)-1) {
8681 return drflac_result_from_errno(errno);
8682 }
8683
8684 pFilePathMB = (char*)drflac__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks);
8685 if (pFilePathMB == NULL) {
8686 return DRFLAC_OUT_OF_MEMORY;
8687 }
8688
8689 pFilePathTemp = pFilePath;
8690 DRFLAC_ZERO_OBJECT(&mbs);
8691 wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs);
8692
8693 /* The open mode should always consist of ASCII characters so we should be able to do a trivial conversion. */
8694 {
8695 size_t i = 0;
8696 for (;;) {
8697 if (pOpenMode[i] == 0) {
8698 pOpenModeMB[i] = '\0';
8699 break;
8700 }
8701
8702 pOpenModeMB[i] = (char)pOpenMode[i];
8703 i += 1;
8704 }
8705 }
8706
8707 *ppFile = fopen(pFilePathMB, pOpenModeMB);
8708
8709 drflac__free_from_callbacks(pFilePathMB, pAllocationCallbacks);
8710 }
8711 #endif
8712
8713 if (*ppFile == NULL) {
8714 return DRFLAC_ERROR;
8715 }
8716#endif
8717
8718 return DRFLAC_SUCCESS;
8719}
8720#endif
8721/* End fopen */
8722
8723static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead)
8724{
8725 return fread(bufferOut, 1, bytesToRead, (FILE*)pUserData);
8726}
8727
8728static drflac_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin)
8729{
8730 DRFLAC_ASSERT(offset >= 0); /* <-- Never seek backwards. */
8731
8732 return fseek((FILE*)pUserData, offset, (origin == drflac_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
8733}
8734
8735
8736DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks)
8737{
8738 drflac* pFlac;
8739 FILE* pFile;
8740
8741 if (drflac_fopen(&pFile, pFileName, "rb") != DRFLAC_SUCCESS) {
8742 return NULL;
8743 }
8744
8745 pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
8746 if (pFlac == NULL) {
8747 fclose(pFile);
8748 return NULL;
8749 }
8750
8751 return pFlac;
8752}
8753
8754#ifndef DR_FLAC_NO_WCHAR
8755DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks)
8756{
8757 drflac* pFlac;
8758 FILE* pFile;
8759
8760 if (drflac_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != DRFLAC_SUCCESS) {
8761 return NULL;
8762 }
8763
8764 pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
8765 if (pFlac == NULL) {
8766 fclose(pFile);
8767 return NULL;
8768 }
8769
8770 return pFlac;
8771}
8772#endif
8773
8774DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
8775{
8776 drflac* pFlac;
8777 FILE* pFile;
8778
8779 if (drflac_fopen(&pFile, pFileName, "rb") != DRFLAC_SUCCESS) {
8780 return NULL;
8781 }
8782
8783 pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks);
8784 if (pFlac == NULL) {
8785 fclose(pFile);
8786 return pFlac;
8787 }
8788
8789 return pFlac;
8790}
8791
8792#ifndef DR_FLAC_NO_WCHAR
8793DRFLAC_API drflac* drflac_open_file_with_metadata_w(const wchar_t* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
8794{
8795 drflac* pFlac;
8796 FILE* pFile;
8797
8798 if (drflac_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != DRFLAC_SUCCESS) {
8799 return NULL;
8800 }
8801
8802 pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks);
8803 if (pFlac == NULL) {
8804 fclose(pFile);
8805 return pFlac;
8806 }
8807
8808 return pFlac;
8809}
8810#endif
8811#endif /* DR_FLAC_NO_STDIO */
8812
8813static size_t drflac__on_read_memory(void* pUserData, void* bufferOut, size_t bytesToRead)
8814{
8815 drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData;
8816 size_t bytesRemaining;
8817
8818 DRFLAC_ASSERT(memoryStream != NULL);
8819 DRFLAC_ASSERT(memoryStream->dataSize >= memoryStream->currentReadPos);
8820
8821 bytesRemaining = memoryStream->dataSize - memoryStream->currentReadPos;
8822 if (bytesToRead > bytesRemaining) {
8823 bytesToRead = bytesRemaining;
8824 }
8825
8826 if (bytesToRead > 0) {
8827 DRFLAC_COPY_MEMORY(bufferOut, memoryStream->data + memoryStream->currentReadPos, bytesToRead);
8828 memoryStream->currentReadPos += bytesToRead;
8829 }
8830
8831 return bytesToRead;
8832}
8833
8834static drflac_bool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_seek_origin origin)
8835{
8836 drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData;
8837
8838 DRFLAC_ASSERT(memoryStream != NULL);
8839 DRFLAC_ASSERT(offset >= 0); /* <-- Never seek backwards. */
8840
8841 if (offset > (drflac_int64)memoryStream->dataSize) {
8842 return DRFLAC_FALSE;
8843 }
8844
8845 if (origin == drflac_seek_origin_current) {
8846 if (memoryStream->currentReadPos + offset <= memoryStream->dataSize) {
8847 memoryStream->currentReadPos += offset;
8848 } else {
8849 return DRFLAC_FALSE; /* Trying to seek too far forward. */
8850 }
8851 } else {
8852 if ((drflac_uint32)offset <= memoryStream->dataSize) {
8853 memoryStream->currentReadPos = offset;
8854 } else {
8855 return DRFLAC_FALSE; /* Trying to seek too far forward. */
8856 }
8857 }
8858
8859 return DRFLAC_TRUE;
8860}
8861
8862DRFLAC_API drflac* drflac_open_memory(const void* pData, size_t dataSize, const drflac_allocation_callbacks* pAllocationCallbacks)
8863{
8864 drflac__memory_stream memoryStream;
8865 drflac* pFlac;
8866
8867 memoryStream.data = (const drflac_uint8*)pData;
8868 memoryStream.dataSize = dataSize;
8869 memoryStream.currentReadPos = 0;
8870 pFlac = drflac_open(drflac__on_read_memory, drflac__on_seek_memory, &memoryStream, pAllocationCallbacks);
8871 if (pFlac == NULL) {
8872 return NULL;
8873 }
8874
8875 pFlac->memoryStream = memoryStream;
8876
8877 /* This is an awful hack... */
8878#ifndef DR_FLAC_NO_OGG
8879 if (pFlac->container == drflac_container_ogg)
8880 {
8881 drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs;
8882 oggbs->pUserData = &pFlac->memoryStream;
8883 }
8884 else
8885#endif
8886 {
8887 pFlac->bs.pUserData = &pFlac->memoryStream;
8888 }
8889
8890 return pFlac;
8891}
8892
8893DRFLAC_API drflac* drflac_open_memory_with_metadata(const void* pData, size_t dataSize, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
8894{
8895 drflac__memory_stream memoryStream;
8896 drflac* pFlac;
8897
8898 memoryStream.data = (const drflac_uint8*)pData;
8899 memoryStream.dataSize = dataSize;
8900 memoryStream.currentReadPos = 0;
8901 pFlac = drflac_open_with_metadata_private(drflac__on_read_memory, drflac__on_seek_memory, onMeta, drflac_container_unknown, &memoryStream, pUserData, pAllocationCallbacks);
8902 if (pFlac == NULL) {
8903 return NULL;
8904 }
8905
8906 pFlac->memoryStream = memoryStream;
8907
8908 /* This is an awful hack... */
8909#ifndef DR_FLAC_NO_OGG
8910 if (pFlac->container == drflac_container_ogg)
8911 {
8912 drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs;
8913 oggbs->pUserData = &pFlac->memoryStream;
8914 }
8915 else
8916#endif
8917 {
8918 pFlac->bs.pUserData = &pFlac->memoryStream;
8919 }
8920
8921 return pFlac;
8922}
8923
8924
8925
8926DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
8927{
8928 return drflac_open_with_metadata_private(onRead, onSeek, NULL, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks);
8929}
8930DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
8931{
8932 return drflac_open_with_metadata_private(onRead, onSeek, NULL, container, pUserData, pUserData, pAllocationCallbacks);
8933}
8934
8935DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
8936{
8937 return drflac_open_with_metadata_private(onRead, onSeek, onMeta, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks);
8938}
8939DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
8940{
8941 return drflac_open_with_metadata_private(onRead, onSeek, onMeta, container, pUserData, pUserData, pAllocationCallbacks);
8942}
8943
8944DRFLAC_API void drflac_close(drflac* pFlac)
8945{
8946 if (pFlac == NULL) {
8947 return;
8948 }
8949
8950#ifndef DR_FLAC_NO_STDIO
8951 /*
8952 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()
8953 was used by looking at the callbacks.
8954 */
8955 if (pFlac->bs.onRead == drflac__on_read_stdio) {
8956 fclose((FILE*)pFlac->bs.pUserData);
8957 }
8958
8959#ifndef DR_FLAC_NO_OGG
8960 /* Need to clean up Ogg streams a bit differently due to the way the bit streaming is chained. */
8961 if (pFlac->container == drflac_container_ogg) {
8962 drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs;
8963 DRFLAC_ASSERT(pFlac->bs.onRead == drflac__on_read_ogg);
8964
8965 if (oggbs->onRead == drflac__on_read_stdio) {
8966 fclose((FILE*)oggbs->pUserData);
8967 }
8968 }
8969#endif
8970#endif
8971
8972 drflac__free_from_callbacks(pFlac, &pFlac->allocationCallbacks);
8973}
8974
8975
8976#if 0
8977static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
8978{
8979 drflac_uint64 i;
8980 for (i = 0; i < frameCount; ++i) {
8981 drflac_uint32 left = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
8982 drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
8983 drflac_uint32 right = left - side;
8984
8985 pOutputSamples[i*2+0] = (drflac_int32)left;
8986 pOutputSamples[i*2+1] = (drflac_int32)right;
8987 }
8988}
8989#endif
8990
8991static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
8992{
8993 drflac_uint64 i;
8994 drflac_uint64 frameCount4 = frameCount >> 2;
8995 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
8996 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
8997 drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
8998 drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
8999
9000 for (i = 0; i < frameCount4; ++i) {
9001 drflac_uint32 left0 = pInputSamples0U32[i*4+0] << shift0;
9002 drflac_uint32 left1 = pInputSamples0U32[i*4+1] << shift0;
9003 drflac_uint32 left2 = pInputSamples0U32[i*4+2] << shift0;
9004 drflac_uint32 left3 = pInputSamples0U32[i*4+3] << shift0;
9005
9006 drflac_uint32 side0 = pInputSamples1U32[i*4+0] << shift1;
9007 drflac_uint32 side1 = pInputSamples1U32[i*4+1] << shift1;
9008 drflac_uint32 side2 = pInputSamples1U32[i*4+2] << shift1;
9009 drflac_uint32 side3 = pInputSamples1U32[i*4+3] << shift1;
9010
9011 drflac_uint32 right0 = left0 - side0;
9012 drflac_uint32 right1 = left1 - side1;
9013 drflac_uint32 right2 = left2 - side2;
9014 drflac_uint32 right3 = left3 - side3;
9015
9016 pOutputSamples[i*8+0] = (drflac_int32)left0;
9017 pOutputSamples[i*8+1] = (drflac_int32)right0;
9018 pOutputSamples[i*8+2] = (drflac_int32)left1;
9019 pOutputSamples[i*8+3] = (drflac_int32)right1;
9020 pOutputSamples[i*8+4] = (drflac_int32)left2;
9021 pOutputSamples[i*8+5] = (drflac_int32)right2;
9022 pOutputSamples[i*8+6] = (drflac_int32)left3;
9023 pOutputSamples[i*8+7] = (drflac_int32)right3;
9024 }
9025
9026 for (i = (frameCount4 << 2); i < frameCount; ++i) {
9027 drflac_uint32 left = pInputSamples0U32[i] << shift0;
9028 drflac_uint32 side = pInputSamples1U32[i] << shift1;
9029 drflac_uint32 right = left - side;
9030
9031 pOutputSamples[i*2+0] = (drflac_int32)left;
9032 pOutputSamples[i*2+1] = (drflac_int32)right;
9033 }
9034}
9035
9036#if defined(DRFLAC_SUPPORT_SSE2)
9037static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
9038{
9039 drflac_uint64 i;
9040 drflac_uint64 frameCount4 = frameCount >> 2;
9041 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
9042 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
9043 drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9044 drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9045
9046 DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
9047
9048 for (i = 0; i < frameCount4; ++i) {
9049 __m128i left = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
9050 __m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
9051 __m128i right = _mm_sub_epi32(left, side);
9052
9053 _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right));
9054 _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right));
9055 }
9056
9057 for (i = (frameCount4 << 2); i < frameCount; ++i) {
9058 drflac_uint32 left = pInputSamples0U32[i] << shift0;
9059 drflac_uint32 side = pInputSamples1U32[i] << shift1;
9060 drflac_uint32 right = left - side;
9061
9062 pOutputSamples[i*2+0] = (drflac_int32)left;
9063 pOutputSamples[i*2+1] = (drflac_int32)right;
9064 }
9065}
9066#endif
9067
9068#if defined(DRFLAC_SUPPORT_NEON)
9069static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
9070{
9071 drflac_uint64 i;
9072 drflac_uint64 frameCount4 = frameCount >> 2;
9073 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
9074 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
9075 drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9076 drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9077 int32x4_t shift0_4;
9078 int32x4_t shift1_4;
9079
9080 DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
9081
9082 shift0_4 = vdupq_n_s32(shift0);
9083 shift1_4 = vdupq_n_s32(shift1);
9084
9085 for (i = 0; i < frameCount4; ++i) {
9086 uint32x4_t left;
9087 uint32x4_t side;
9088 uint32x4_t right;
9089
9090 left = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
9091 side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
9092 right = vsubq_u32(left, side);
9093
9094 drflac__vst2q_u32((drflac_uint32*)pOutputSamples + i*8, vzipq_u32(left, right));
9095 }
9096
9097 for (i = (frameCount4 << 2); i < frameCount; ++i) {
9098 drflac_uint32 left = pInputSamples0U32[i] << shift0;
9099 drflac_uint32 side = pInputSamples1U32[i] << shift1;
9100 drflac_uint32 right = left - side;
9101
9102 pOutputSamples[i*2+0] = (drflac_int32)left;
9103 pOutputSamples[i*2+1] = (drflac_int32)right;
9104 }
9105}
9106#endif
9107
9108static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
9109{
9110#if defined(DRFLAC_SUPPORT_SSE2)
9111 if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
9112 drflac_read_pcm_frames_s32__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
9113 } else
9114#elif defined(DRFLAC_SUPPORT_NEON)
9115 if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
9116 drflac_read_pcm_frames_s32__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
9117 } else
9118#endif
9119 {
9120 /* Scalar fallback. */
9121#if 0
9122 drflac_read_pcm_frames_s32__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
9123#else
9124 drflac_read_pcm_frames_s32__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
9125#endif
9126 }
9127}
9128
9129
9130#if 0
9131static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
9132{
9133 drflac_uint64 i;
9134 for (i = 0; i < frameCount; ++i) {
9135 drflac_uint32 side = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
9136 drflac_uint32 right = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
9137 drflac_uint32 left = right + side;
9138
9139 pOutputSamples[i*2+0] = (drflac_int32)left;
9140 pOutputSamples[i*2+1] = (drflac_int32)right;
9141 }
9142}
9143#endif
9144
9145static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
9146{
9147 drflac_uint64 i;
9148 drflac_uint64 frameCount4 = frameCount >> 2;
9149 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
9150 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
9151 drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9152 drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9153
9154 for (i = 0; i < frameCount4; ++i) {
9155 drflac_uint32 side0 = pInputSamples0U32[i*4+0] << shift0;
9156 drflac_uint32 side1 = pInputSamples0U32[i*4+1] << shift0;
9157 drflac_uint32 side2 = pInputSamples0U32[i*4+2] << shift0;
9158 drflac_uint32 side3 = pInputSamples0U32[i*4+3] << shift0;
9159
9160 drflac_uint32 right0 = pInputSamples1U32[i*4+0] << shift1;
9161 drflac_uint32 right1 = pInputSamples1U32[i*4+1] << shift1;
9162 drflac_uint32 right2 = pInputSamples1U32[i*4+2] << shift1;
9163 drflac_uint32 right3 = pInputSamples1U32[i*4+3] << shift1;
9164
9165 drflac_uint32 left0 = right0 + side0;
9166 drflac_uint32 left1 = right1 + side1;
9167 drflac_uint32 left2 = right2 + side2;
9168 drflac_uint32 left3 = right3 + side3;
9169
9170 pOutputSamples[i*8+0] = (drflac_int32)left0;
9171 pOutputSamples[i*8+1] = (drflac_int32)right0;
9172 pOutputSamples[i*8+2] = (drflac_int32)left1;
9173 pOutputSamples[i*8+3] = (drflac_int32)right1;
9174 pOutputSamples[i*8+4] = (drflac_int32)left2;
9175 pOutputSamples[i*8+5] = (drflac_int32)right2;
9176 pOutputSamples[i*8+6] = (drflac_int32)left3;
9177 pOutputSamples[i*8+7] = (drflac_int32)right3;
9178 }
9179
9180 for (i = (frameCount4 << 2); i < frameCount; ++i) {
9181 drflac_uint32 side = pInputSamples0U32[i] << shift0;
9182 drflac_uint32 right = pInputSamples1U32[i] << shift1;
9183 drflac_uint32 left = right + side;
9184
9185 pOutputSamples[i*2+0] = (drflac_int32)left;
9186 pOutputSamples[i*2+1] = (drflac_int32)right;
9187 }
9188}
9189
9190#if defined(DRFLAC_SUPPORT_SSE2)
9191static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
9192{
9193 drflac_uint64 i;
9194 drflac_uint64 frameCount4 = frameCount >> 2;
9195 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
9196 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
9197 drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9198 drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9199
9200 DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
9201
9202 for (i = 0; i < frameCount4; ++i) {
9203 __m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
9204 __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
9205 __m128i left = _mm_add_epi32(right, side);
9206
9207 _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right));
9208 _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right));
9209 }
9210
9211 for (i = (frameCount4 << 2); i < frameCount; ++i) {
9212 drflac_uint32 side = pInputSamples0U32[i] << shift0;
9213 drflac_uint32 right = pInputSamples1U32[i] << shift1;
9214 drflac_uint32 left = right + side;
9215
9216 pOutputSamples[i*2+0] = (drflac_int32)left;
9217 pOutputSamples[i*2+1] = (drflac_int32)right;
9218 }
9219}
9220#endif
9221
9222#if defined(DRFLAC_SUPPORT_NEON)
9223static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
9224{
9225 drflac_uint64 i;
9226 drflac_uint64 frameCount4 = frameCount >> 2;
9227 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
9228 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
9229 drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9230 drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9231 int32x4_t shift0_4;
9232 int32x4_t shift1_4;
9233
9234 DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
9235
9236 shift0_4 = vdupq_n_s32(shift0);
9237 shift1_4 = vdupq_n_s32(shift1);
9238
9239 for (i = 0; i < frameCount4; ++i) {
9240 uint32x4_t side;
9241 uint32x4_t right;
9242 uint32x4_t left;
9243
9244 side = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
9245 right = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
9246 left = vaddq_u32(right, side);
9247
9248 drflac__vst2q_u32((drflac_uint32*)pOutputSamples + i*8, vzipq_u32(left, right));
9249 }
9250
9251 for (i = (frameCount4 << 2); i < frameCount; ++i) {
9252 drflac_uint32 side = pInputSamples0U32[i] << shift0;
9253 drflac_uint32 right = pInputSamples1U32[i] << shift1;
9254 drflac_uint32 left = right + side;
9255
9256 pOutputSamples[i*2+0] = (drflac_int32)left;
9257 pOutputSamples[i*2+1] = (drflac_int32)right;
9258 }
9259}
9260#endif
9261
9262static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
9263{
9264#if defined(DRFLAC_SUPPORT_SSE2)
9265 if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
9266 drflac_read_pcm_frames_s32__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
9267 } else
9268#elif defined(DRFLAC_SUPPORT_NEON)
9269 if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
9270 drflac_read_pcm_frames_s32__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
9271 } else
9272#endif
9273 {
9274 /* Scalar fallback. */
9275#if 0
9276 drflac_read_pcm_frames_s32__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
9277#else
9278 drflac_read_pcm_frames_s32__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
9279#endif
9280 }
9281}
9282
9283
9284#if 0
9285static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
9286{
9287 for (drflac_uint64 i = 0; i < frameCount; ++i) {
9288 drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9289 drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9290
9291 mid = (mid << 1) | (side & 0x01);
9292
9293 pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample);
9294 pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample);
9295 }
9296}
9297#endif
9298
9299static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
9300{
9301 drflac_uint64 i;
9302 drflac_uint64 frameCount4 = frameCount >> 2;
9303 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
9304 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
9305 drflac_int32 shift = unusedBitsPerSample;
9306
9307 if (shift > 0) {
9308 shift -= 1;
9309 for (i = 0; i < frameCount4; ++i) {
9310 drflac_uint32 temp0L;
9311 drflac_uint32 temp1L;
9312 drflac_uint32 temp2L;
9313 drflac_uint32 temp3L;
9314 drflac_uint32 temp0R;
9315 drflac_uint32 temp1R;
9316 drflac_uint32 temp2R;
9317 drflac_uint32 temp3R;
9318
9319 drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9320 drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9321 drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9322 drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9323
9324 drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9325 drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9326 drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9327 drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9328
9329 mid0 = (mid0 << 1) | (side0 & 0x01);
9330 mid1 = (mid1 << 1) | (side1 & 0x01);
9331 mid2 = (mid2 << 1) | (side2 & 0x01);
9332 mid3 = (mid3 << 1) | (side3 & 0x01);
9333
9334 temp0L = (mid0 + side0) << shift;
9335 temp1L = (mid1 + side1) << shift;
9336 temp2L = (mid2 + side2) << shift;
9337 temp3L = (mid3 + side3) << shift;
9338
9339 temp0R = (mid0 - side0) << shift;
9340 temp1R = (mid1 - side1) << shift;
9341 temp2R = (mid2 - side2) << shift;
9342 temp3R = (mid3 - side3) << shift;
9343
9344 pOutputSamples[i*8+0] = (drflac_int32)temp0L;
9345 pOutputSamples[i*8+1] = (drflac_int32)temp0R;
9346 pOutputSamples[i*8+2] = (drflac_int32)temp1L;
9347 pOutputSamples[i*8+3] = (drflac_int32)temp1R;
9348 pOutputSamples[i*8+4] = (drflac_int32)temp2L;
9349 pOutputSamples[i*8+5] = (drflac_int32)temp2R;
9350 pOutputSamples[i*8+6] = (drflac_int32)temp3L;
9351 pOutputSamples[i*8+7] = (drflac_int32)temp3R;
9352 }
9353 } else {
9354 for (i = 0; i < frameCount4; ++i) {
9355 drflac_uint32 temp0L;
9356 drflac_uint32 temp1L;
9357 drflac_uint32 temp2L;
9358 drflac_uint32 temp3L;
9359 drflac_uint32 temp0R;
9360 drflac_uint32 temp1R;
9361 drflac_uint32 temp2R;
9362 drflac_uint32 temp3R;
9363
9364 drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9365 drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9366 drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9367 drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9368
9369 drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9370 drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9371 drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9372 drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9373
9374 mid0 = (mid0 << 1) | (side0 & 0x01);
9375 mid1 = (mid1 << 1) | (side1 & 0x01);
9376 mid2 = (mid2 << 1) | (side2 & 0x01);
9377 mid3 = (mid3 << 1) | (side3 & 0x01);
9378
9379 temp0L = (drflac_uint32)((drflac_int32)(mid0 + side0) >> 1);
9380 temp1L = (drflac_uint32)((drflac_int32)(mid1 + side1) >> 1);
9381 temp2L = (drflac_uint32)((drflac_int32)(mid2 + side2) >> 1);
9382 temp3L = (drflac_uint32)((drflac_int32)(mid3 + side3) >> 1);
9383
9384 temp0R = (drflac_uint32)((drflac_int32)(mid0 - side0) >> 1);
9385 temp1R = (drflac_uint32)((drflac_int32)(mid1 - side1) >> 1);
9386 temp2R = (drflac_uint32)((drflac_int32)(mid2 - side2) >> 1);
9387 temp3R = (drflac_uint32)((drflac_int32)(mid3 - side3) >> 1);
9388
9389 pOutputSamples[i*8+0] = (drflac_int32)temp0L;
9390 pOutputSamples[i*8+1] = (drflac_int32)temp0R;
9391 pOutputSamples[i*8+2] = (drflac_int32)temp1L;
9392 pOutputSamples[i*8+3] = (drflac_int32)temp1R;
9393 pOutputSamples[i*8+4] = (drflac_int32)temp2L;
9394 pOutputSamples[i*8+5] = (drflac_int32)temp2R;
9395 pOutputSamples[i*8+6] = (drflac_int32)temp3L;
9396 pOutputSamples[i*8+7] = (drflac_int32)temp3R;
9397 }
9398 }
9399
9400 for (i = (frameCount4 << 2); i < frameCount; ++i) {
9401 drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9402 drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9403
9404 mid = (mid << 1) | (side & 0x01);
9405
9406 pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample);
9407 pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample);
9408 }
9409}
9410
9411#if defined(DRFLAC_SUPPORT_SSE2)
9412static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
9413{
9414 drflac_uint64 i;
9415 drflac_uint64 frameCount4 = frameCount >> 2;
9416 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
9417 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
9418 drflac_int32 shift = unusedBitsPerSample;
9419
9420 DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
9421
9422 if (shift == 0) {
9423 for (i = 0; i < frameCount4; ++i) {
9424 __m128i mid;
9425 __m128i side;
9426 __m128i left;
9427 __m128i right;
9428
9429 mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
9430 side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
9431
9432 mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
9433
9434 left = _mm_srai_epi32(_mm_add_epi32(mid, side), 1);
9435 right = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1);
9436
9437 _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right));
9438 _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right));
9439 }
9440
9441 for (i = (frameCount4 << 2); i < frameCount; ++i) {
9442 drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9443 drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9444
9445 mid = (mid << 1) | (side & 0x01);
9446
9447 pOutputSamples[i*2+0] = (drflac_int32)(mid + side) >> 1;
9448 pOutputSamples[i*2+1] = (drflac_int32)(mid - side) >> 1;
9449 }
9450 } else {
9451 shift -= 1;
9452 for (i = 0; i < frameCount4; ++i) {
9453 __m128i mid;
9454 __m128i side;
9455 __m128i left;
9456 __m128i right;
9457
9458 mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
9459 side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
9460
9461 mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
9462
9463 left = _mm_slli_epi32(_mm_add_epi32(mid, side), shift);
9464 right = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift);
9465
9466 _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right));
9467 _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right));
9468 }
9469
9470 for (i = (frameCount4 << 2); i < frameCount; ++i) {
9471 drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9472 drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9473
9474 mid = (mid << 1) | (side & 0x01);
9475
9476 pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift);
9477 pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift);
9478 }
9479 }
9480}
9481#endif
9482
9483#if defined(DRFLAC_SUPPORT_NEON)
9484static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
9485{
9486 drflac_uint64 i;
9487 drflac_uint64 frameCount4 = frameCount >> 2;
9488 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
9489 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
9490 drflac_int32 shift = unusedBitsPerSample;
9491 int32x4_t wbpsShift0_4; /* wbps = Wasted Bits Per Sample */
9492 int32x4_t wbpsShift1_4; /* wbps = Wasted Bits Per Sample */
9493 uint32x4_t one4;
9494
9495 DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
9496
9497 wbpsShift0_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
9498 wbpsShift1_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
9499 one4 = vdupq_n_u32(1);
9500
9501 if (shift == 0) {
9502 for (i = 0; i < frameCount4; ++i) {
9503 uint32x4_t mid;
9504 uint32x4_t side;
9505 int32x4_t left;
9506 int32x4_t right;
9507
9508 mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4);
9509 side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4);
9510
9511 mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, one4));
9512
9513 left = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1);
9514 right = vshrq_n_s32(vreinterpretq_s32_u32(vsubq_u32(mid, side)), 1);
9515
9516 drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right));
9517 }
9518
9519 for (i = (frameCount4 << 2); i < frameCount; ++i) {
9520 drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9521 drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9522
9523 mid = (mid << 1) | (side & 0x01);
9524
9525 pOutputSamples[i*2+0] = (drflac_int32)(mid + side) >> 1;
9526 pOutputSamples[i*2+1] = (drflac_int32)(mid - side) >> 1;
9527 }
9528 } else {
9529 int32x4_t shift4;
9530
9531 shift -= 1;
9532 shift4 = vdupq_n_s32(shift);
9533
9534 for (i = 0; i < frameCount4; ++i) {
9535 uint32x4_t mid;
9536 uint32x4_t side;
9537 int32x4_t left;
9538 int32x4_t right;
9539
9540 mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4);
9541 side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4);
9542
9543 mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, one4));
9544
9545 left = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4));
9546 right = vreinterpretq_s32_u32(vshlq_u32(vsubq_u32(mid, side), shift4));
9547
9548 drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right));
9549 }
9550
9551 for (i = (frameCount4 << 2); i < frameCount; ++i) {
9552 drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9553 drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9554
9555 mid = (mid << 1) | (side & 0x01);
9556
9557 pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift);
9558 pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift);
9559 }
9560 }
9561}
9562#endif
9563
9564static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
9565{
9566#if defined(DRFLAC_SUPPORT_SSE2)
9567 if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
9568 drflac_read_pcm_frames_s32__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
9569 } else
9570#elif defined(DRFLAC_SUPPORT_NEON)
9571 if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
9572 drflac_read_pcm_frames_s32__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
9573 } else
9574#endif
9575 {
9576 /* Scalar fallback. */
9577#if 0
9578 drflac_read_pcm_frames_s32__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
9579#else
9580 drflac_read_pcm_frames_s32__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
9581#endif
9582 }
9583}
9584
9585
9586#if 0
9587static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
9588{
9589 for (drflac_uint64 i = 0; i < frameCount; ++i) {
9590 pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample));
9591 pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample));
9592 }
9593}
9594#endif
9595
9596static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
9597{
9598 drflac_uint64 i;
9599 drflac_uint64 frameCount4 = frameCount >> 2;
9600 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
9601 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
9602 drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9603 drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9604
9605 for (i = 0; i < frameCount4; ++i) {
9606 drflac_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0;
9607 drflac_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0;
9608 drflac_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0;
9609 drflac_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0;
9610
9611 drflac_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1;
9612 drflac_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1;
9613 drflac_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1;
9614 drflac_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1;
9615
9616 pOutputSamples[i*8+0] = (drflac_int32)tempL0;
9617 pOutputSamples[i*8+1] = (drflac_int32)tempR0;
9618 pOutputSamples[i*8+2] = (drflac_int32)tempL1;
9619 pOutputSamples[i*8+3] = (drflac_int32)tempR1;
9620 pOutputSamples[i*8+4] = (drflac_int32)tempL2;
9621 pOutputSamples[i*8+5] = (drflac_int32)tempR2;
9622 pOutputSamples[i*8+6] = (drflac_int32)tempL3;
9623 pOutputSamples[i*8+7] = (drflac_int32)tempR3;
9624 }
9625
9626 for (i = (frameCount4 << 2); i < frameCount; ++i) {
9627 pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0);
9628 pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1);
9629 }
9630}
9631
9632#if defined(DRFLAC_SUPPORT_SSE2)
9633static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
9634{
9635 drflac_uint64 i;
9636 drflac_uint64 frameCount4 = frameCount >> 2;
9637 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
9638 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
9639 drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9640 drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9641
9642 for (i = 0; i < frameCount4; ++i) {
9643 __m128i left = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
9644 __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
9645
9646 _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right));
9647 _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right));
9648 }
9649
9650 for (i = (frameCount4 << 2); i < frameCount; ++i) {
9651 pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0);
9652 pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1);
9653 }
9654}
9655#endif
9656
9657#if defined(DRFLAC_SUPPORT_NEON)
9658static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
9659{
9660 drflac_uint64 i;
9661 drflac_uint64 frameCount4 = frameCount >> 2;
9662 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
9663 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
9664 drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9665 drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9666
9667 int32x4_t shift4_0 = vdupq_n_s32(shift0);
9668 int32x4_t shift4_1 = vdupq_n_s32(shift1);
9669
9670 for (i = 0; i < frameCount4; ++i) {
9671 int32x4_t left;
9672 int32x4_t right;
9673
9674 left = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift4_0));
9675 right = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift4_1));
9676
9677 drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right));
9678 }
9679
9680 for (i = (frameCount4 << 2); i < frameCount; ++i) {
9681 pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0);
9682 pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1);
9683 }
9684}
9685#endif
9686
9687static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
9688{
9689#if defined(DRFLAC_SUPPORT_SSE2)
9690 if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
9691 drflac_read_pcm_frames_s32__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
9692 } else
9693#elif defined(DRFLAC_SUPPORT_NEON)
9694 if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
9695 drflac_read_pcm_frames_s32__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
9696 } else
9697#endif
9698 {
9699 /* Scalar fallback. */
9700#if 0
9701 drflac_read_pcm_frames_s32__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
9702#else
9703 drflac_read_pcm_frames_s32__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
9704#endif
9705 }
9706}
9707
9708
9709DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s32(drflac* pFlac, drflac_uint64 framesToRead, drflac_int32* pBufferOut)
9710{
9711 drflac_uint64 framesRead;
9712 drflac_uint32 unusedBitsPerSample;
9713
9714 if (pFlac == NULL || framesToRead == 0) {
9715 return 0;
9716 }
9717
9718 if (pBufferOut == NULL) {
9719 return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead);
9720 }
9721
9722 DRFLAC_ASSERT(pFlac->bitsPerSample <= 32);
9723 unusedBitsPerSample = 32 - pFlac->bitsPerSample;
9724
9725 framesRead = 0;
9726 while (framesToRead > 0) {
9727 /* If we've run out of samples in this frame, go to the next. */
9728 if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
9729 if (!drflac__read_and_decode_next_flac_frame(pFlac)) {
9730 break; /* Couldn't read the next frame, so just break from the loop and return. */
9731 }
9732 } else {
9733 unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment);
9734 drflac_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining;
9735 drflac_uint64 frameCountThisIteration = framesToRead;
9736
9737 if (frameCountThisIteration > pFlac->currentFLACFrame.pcmFramesRemaining) {
9738 frameCountThisIteration = pFlac->currentFLACFrame.pcmFramesRemaining;
9739 }
9740
9741 if (channelCount == 2) {
9742 const drflac_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame;
9743 const drflac_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame;
9744
9745 switch (pFlac->currentFLACFrame.header.channelAssignment)
9746 {
9747 case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE:
9748 {
9749 drflac_read_pcm_frames_s32__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
9750 } break;
9751
9752 case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE:
9753 {
9754 drflac_read_pcm_frames_s32__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
9755 } break;
9756
9757 case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE:
9758 {
9759 drflac_read_pcm_frames_s32__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
9760 } break;
9761
9762 case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT:
9763 default:
9764 {
9765 drflac_read_pcm_frames_s32__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
9766 } break;
9767 }
9768 } else {
9769 /* Generic interleaving. */
9770 drflac_uint64 i;
9771 for (i = 0; i < frameCountThisIteration; ++i) {
9772 unsigned int j;
9773 for (j = 0; j < channelCount; ++j) {
9774 pBufferOut[(i*channelCount)+j] = (drflac_int32)((drflac_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample));
9775 }
9776 }
9777 }
9778
9779 framesRead += frameCountThisIteration;
9780 pBufferOut += frameCountThisIteration * channelCount;
9781 framesToRead -= frameCountThisIteration;
9782 pFlac->currentPCMFrame += frameCountThisIteration;
9783 pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)frameCountThisIteration;
9784 }
9785 }
9786
9787 return framesRead;
9788}
9789
9790
9791#if 0
9792static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
9793{
9794 drflac_uint64 i;
9795 for (i = 0; i < frameCount; ++i) {
9796 drflac_uint32 left = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
9797 drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
9798 drflac_uint32 right = left - side;
9799
9800 left >>= 16;
9801 right >>= 16;
9802
9803 pOutputSamples[i*2+0] = (drflac_int16)left;
9804 pOutputSamples[i*2+1] = (drflac_int16)right;
9805 }
9806}
9807#endif
9808
9809static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
9810{
9811 drflac_uint64 i;
9812 drflac_uint64 frameCount4 = frameCount >> 2;
9813 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
9814 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
9815 drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9816 drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9817
9818 for (i = 0; i < frameCount4; ++i) {
9819 drflac_uint32 left0 = pInputSamples0U32[i*4+0] << shift0;
9820 drflac_uint32 left1 = pInputSamples0U32[i*4+1] << shift0;
9821 drflac_uint32 left2 = pInputSamples0U32[i*4+2] << shift0;
9822 drflac_uint32 left3 = pInputSamples0U32[i*4+3] << shift0;
9823
9824 drflac_uint32 side0 = pInputSamples1U32[i*4+0] << shift1;
9825 drflac_uint32 side1 = pInputSamples1U32[i*4+1] << shift1;
9826 drflac_uint32 side2 = pInputSamples1U32[i*4+2] << shift1;
9827 drflac_uint32 side3 = pInputSamples1U32[i*4+3] << shift1;
9828
9829 drflac_uint32 right0 = left0 - side0;
9830 drflac_uint32 right1 = left1 - side1;
9831 drflac_uint32 right2 = left2 - side2;
9832 drflac_uint32 right3 = left3 - side3;
9833
9834 left0 >>= 16;
9835 left1 >>= 16;
9836 left2 >>= 16;
9837 left3 >>= 16;
9838
9839 right0 >>= 16;
9840 right1 >>= 16;
9841 right2 >>= 16;
9842 right3 >>= 16;
9843
9844 pOutputSamples[i*8+0] = (drflac_int16)left0;
9845 pOutputSamples[i*8+1] = (drflac_int16)right0;
9846 pOutputSamples[i*8+2] = (drflac_int16)left1;
9847 pOutputSamples[i*8+3] = (drflac_int16)right1;
9848 pOutputSamples[i*8+4] = (drflac_int16)left2;
9849 pOutputSamples[i*8+5] = (drflac_int16)right2;
9850 pOutputSamples[i*8+6] = (drflac_int16)left3;
9851 pOutputSamples[i*8+7] = (drflac_int16)right3;
9852 }
9853
9854 for (i = (frameCount4 << 2); i < frameCount; ++i) {
9855 drflac_uint32 left = pInputSamples0U32[i] << shift0;
9856 drflac_uint32 side = pInputSamples1U32[i] << shift1;
9857 drflac_uint32 right = left - side;
9858
9859 left >>= 16;
9860 right >>= 16;
9861
9862 pOutputSamples[i*2+0] = (drflac_int16)left;
9863 pOutputSamples[i*2+1] = (drflac_int16)right;
9864 }
9865}
9866
9867#if defined(DRFLAC_SUPPORT_SSE2)
9868static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
9869{
9870 drflac_uint64 i;
9871 drflac_uint64 frameCount4 = frameCount >> 2;
9872 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
9873 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
9874 drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9875 drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9876
9877 DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
9878
9879 for (i = 0; i < frameCount4; ++i) {
9880 __m128i left = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
9881 __m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
9882 __m128i right = _mm_sub_epi32(left, side);
9883
9884 left = _mm_srai_epi32(left, 16);
9885 right = _mm_srai_epi32(right, 16);
9886
9887 _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right));
9888 }
9889
9890 for (i = (frameCount4 << 2); i < frameCount; ++i) {
9891 drflac_uint32 left = pInputSamples0U32[i] << shift0;
9892 drflac_uint32 side = pInputSamples1U32[i] << shift1;
9893 drflac_uint32 right = left - side;
9894
9895 left >>= 16;
9896 right >>= 16;
9897
9898 pOutputSamples[i*2+0] = (drflac_int16)left;
9899 pOutputSamples[i*2+1] = (drflac_int16)right;
9900 }
9901}
9902#endif
9903
9904#if defined(DRFLAC_SUPPORT_NEON)
9905static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
9906{
9907 drflac_uint64 i;
9908 drflac_uint64 frameCount4 = frameCount >> 2;
9909 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
9910 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
9911 drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9912 drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9913 int32x4_t shift0_4;
9914 int32x4_t shift1_4;
9915
9916 DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
9917
9918 shift0_4 = vdupq_n_s32(shift0);
9919 shift1_4 = vdupq_n_s32(shift1);
9920
9921 for (i = 0; i < frameCount4; ++i) {
9922 uint32x4_t left;
9923 uint32x4_t side;
9924 uint32x4_t right;
9925
9926 left = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
9927 side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
9928 right = vsubq_u32(left, side);
9929
9930 left = vshrq_n_u32(left, 16);
9931 right = vshrq_n_u32(right, 16);
9932
9933 drflac__vst2q_u16((drflac_uint16*)pOutputSamples + i*8, vzip_u16(vmovn_u32(left), vmovn_u32(right)));
9934 }
9935
9936 for (i = (frameCount4 << 2); i < frameCount; ++i) {
9937 drflac_uint32 left = pInputSamples0U32[i] << shift0;
9938 drflac_uint32 side = pInputSamples1U32[i] << shift1;
9939 drflac_uint32 right = left - side;
9940
9941 left >>= 16;
9942 right >>= 16;
9943
9944 pOutputSamples[i*2+0] = (drflac_int16)left;
9945 pOutputSamples[i*2+1] = (drflac_int16)right;
9946 }
9947}
9948#endif
9949
9950static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
9951{
9952#if defined(DRFLAC_SUPPORT_SSE2)
9953 if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
9954 drflac_read_pcm_frames_s16__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
9955 } else
9956#elif defined(DRFLAC_SUPPORT_NEON)
9957 if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
9958 drflac_read_pcm_frames_s16__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
9959 } else
9960#endif
9961 {
9962 /* Scalar fallback. */
9963#if 0
9964 drflac_read_pcm_frames_s16__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
9965#else
9966 drflac_read_pcm_frames_s16__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
9967#endif
9968 }
9969}
9970
9971
9972#if 0
9973static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
9974{
9975 drflac_uint64 i;
9976 for (i = 0; i < frameCount; ++i) {
9977 drflac_uint32 side = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
9978 drflac_uint32 right = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
9979 drflac_uint32 left = right + side;
9980
9981 left >>= 16;
9982 right >>= 16;
9983
9984 pOutputSamples[i*2+0] = (drflac_int16)left;
9985 pOutputSamples[i*2+1] = (drflac_int16)right;
9986 }
9987}
9988#endif
9989
9990static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
9991{
9992 drflac_uint64 i;
9993 drflac_uint64 frameCount4 = frameCount >> 2;
9994 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
9995 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
9996 drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
9997 drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
9998
9999 for (i = 0; i < frameCount4; ++i) {
10000 drflac_uint32 side0 = pInputSamples0U32[i*4+0] << shift0;
10001 drflac_uint32 side1 = pInputSamples0U32[i*4+1] << shift0;
10002 drflac_uint32 side2 = pInputSamples0U32[i*4+2] << shift0;
10003 drflac_uint32 side3 = pInputSamples0U32[i*4+3] << shift0;
10004
10005 drflac_uint32 right0 = pInputSamples1U32[i*4+0] << shift1;
10006 drflac_uint32 right1 = pInputSamples1U32[i*4+1] << shift1;
10007 drflac_uint32 right2 = pInputSamples1U32[i*4+2] << shift1;
10008 drflac_uint32 right3 = pInputSamples1U32[i*4+3] << shift1;
10009
10010 drflac_uint32 left0 = right0 + side0;
10011 drflac_uint32 left1 = right1 + side1;
10012 drflac_uint32 left2 = right2 + side2;
10013 drflac_uint32 left3 = right3 + side3;
10014
10015 left0 >>= 16;
10016 left1 >>= 16;
10017 left2 >>= 16;
10018 left3 >>= 16;
10019
10020 right0 >>= 16;
10021 right1 >>= 16;
10022 right2 >>= 16;
10023 right3 >>= 16;
10024
10025 pOutputSamples[i*8+0] = (drflac_int16)left0;
10026 pOutputSamples[i*8+1] = (drflac_int16)right0;
10027 pOutputSamples[i*8+2] = (drflac_int16)left1;
10028 pOutputSamples[i*8+3] = (drflac_int16)right1;
10029 pOutputSamples[i*8+4] = (drflac_int16)left2;
10030 pOutputSamples[i*8+5] = (drflac_int16)right2;
10031 pOutputSamples[i*8+6] = (drflac_int16)left3;
10032 pOutputSamples[i*8+7] = (drflac_int16)right3;
10033 }
10034
10035 for (i = (frameCount4 << 2); i < frameCount; ++i) {
10036 drflac_uint32 side = pInputSamples0U32[i] << shift0;
10037 drflac_uint32 right = pInputSamples1U32[i] << shift1;
10038 drflac_uint32 left = right + side;
10039
10040 left >>= 16;
10041 right >>= 16;
10042
10043 pOutputSamples[i*2+0] = (drflac_int16)left;
10044 pOutputSamples[i*2+1] = (drflac_int16)right;
10045 }
10046}
10047
10048#if defined(DRFLAC_SUPPORT_SSE2)
10049static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
10050{
10051 drflac_uint64 i;
10052 drflac_uint64 frameCount4 = frameCount >> 2;
10053 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
10054 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
10055 drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
10056 drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
10057
10058 DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
10059
10060 for (i = 0; i < frameCount4; ++i) {
10061 __m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
10062 __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
10063 __m128i left = _mm_add_epi32(right, side);
10064
10065 left = _mm_srai_epi32(left, 16);
10066 right = _mm_srai_epi32(right, 16);
10067
10068 _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right));
10069 }
10070
10071 for (i = (frameCount4 << 2); i < frameCount; ++i) {
10072 drflac_uint32 side = pInputSamples0U32[i] << shift0;
10073 drflac_uint32 right = pInputSamples1U32[i] << shift1;
10074 drflac_uint32 left = right + side;
10075
10076 left >>= 16;
10077 right >>= 16;
10078
10079 pOutputSamples[i*2+0] = (drflac_int16)left;
10080 pOutputSamples[i*2+1] = (drflac_int16)right;
10081 }
10082}
10083#endif
10084
10085#if defined(DRFLAC_SUPPORT_NEON)
10086static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
10087{
10088 drflac_uint64 i;
10089 drflac_uint64 frameCount4 = frameCount >> 2;
10090 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
10091 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
10092 drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
10093 drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
10094 int32x4_t shift0_4;
10095 int32x4_t shift1_4;
10096
10097 DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
10098
10099 shift0_4 = vdupq_n_s32(shift0);
10100 shift1_4 = vdupq_n_s32(shift1);
10101
10102 for (i = 0; i < frameCount4; ++i) {
10103 uint32x4_t side;
10104 uint32x4_t right;
10105 uint32x4_t left;
10106
10107 side = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
10108 right = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
10109 left = vaddq_u32(right, side);
10110
10111 left = vshrq_n_u32(left, 16);
10112 right = vshrq_n_u32(right, 16);
10113
10114 drflac__vst2q_u16((drflac_uint16*)pOutputSamples + i*8, vzip_u16(vmovn_u32(left), vmovn_u32(right)));
10115 }
10116
10117 for (i = (frameCount4 << 2); i < frameCount; ++i) {
10118 drflac_uint32 side = pInputSamples0U32[i] << shift0;
10119 drflac_uint32 right = pInputSamples1U32[i] << shift1;
10120 drflac_uint32 left = right + side;
10121
10122 left >>= 16;
10123 right >>= 16;
10124
10125 pOutputSamples[i*2+0] = (drflac_int16)left;
10126 pOutputSamples[i*2+1] = (drflac_int16)right;
10127 }
10128}
10129#endif
10130
10131static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
10132{
10133#if defined(DRFLAC_SUPPORT_SSE2)
10134 if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
10135 drflac_read_pcm_frames_s16__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
10136 } else
10137#elif defined(DRFLAC_SUPPORT_NEON)
10138 if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
10139 drflac_read_pcm_frames_s16__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
10140 } else
10141#endif
10142 {
10143 /* Scalar fallback. */
10144#if 0
10145 drflac_read_pcm_frames_s16__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
10146#else
10147 drflac_read_pcm_frames_s16__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
10148#endif
10149 }
10150}
10151
10152
10153#if 0
10154static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
10155{
10156 for (drflac_uint64 i = 0; i < frameCount; ++i) {
10157 drflac_uint32 mid = (drflac_uint32)pInputSamples0[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
10158 drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
10159
10160 mid = (mid << 1) | (side & 0x01);
10161
10162 pOutputSamples[i*2+0] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample) >> 16);
10163 pOutputSamples[i*2+1] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample) >> 16);
10164 }
10165}
10166#endif
10167
10168static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
10169{
10170 drflac_uint64 i;
10171 drflac_uint64 frameCount4 = frameCount >> 2;
10172 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
10173 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
10174 drflac_uint32 shift = unusedBitsPerSample;
10175
10176 if (shift > 0) {
10177 shift -= 1;
10178 for (i = 0; i < frameCount4; ++i) {
10179 drflac_uint32 temp0L;
10180 drflac_uint32 temp1L;
10181 drflac_uint32 temp2L;
10182 drflac_uint32 temp3L;
10183 drflac_uint32 temp0R;
10184 drflac_uint32 temp1R;
10185 drflac_uint32 temp2R;
10186 drflac_uint32 temp3R;
10187
10188 drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
10189 drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
10190 drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
10191 drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
10192
10193 drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
10194 drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
10195 drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
10196 drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
10197
10198 mid0 = (mid0 << 1) | (side0 & 0x01);
10199 mid1 = (mid1 << 1) | (side1 & 0x01);
10200 mid2 = (mid2 << 1) | (side2 & 0x01);
10201 mid3 = (mid3 << 1) | (side3 & 0x01);
10202
10203 temp0L = (mid0 + side0) << shift;
10204 temp1L = (mid1 + side1) << shift;
10205 temp2L = (mid2 + side2) << shift;
10206 temp3L = (mid3 + side3) << shift;
10207
10208 temp0R = (mid0 - side0) << shift;
10209 temp1R = (mid1 - side1) << shift;
10210 temp2R = (mid2 - side2) << shift;
10211 temp3R = (mid3 - side3) << shift;
10212
10213 temp0L >>= 16;
10214 temp1L >>= 16;
10215 temp2L >>= 16;
10216 temp3L >>= 16;
10217
10218 temp0R >>= 16;
10219 temp1R >>= 16;
10220 temp2R >>= 16;
10221 temp3R >>= 16;
10222
10223 pOutputSamples[i*8+0] = (drflac_int16)temp0L;
10224 pOutputSamples[i*8+1] = (drflac_int16)temp0R;
10225 pOutputSamples[i*8+2] = (drflac_int16)temp1L;
10226 pOutputSamples[i*8+3] = (drflac_int16)temp1R;
10227 pOutputSamples[i*8+4] = (drflac_int16)temp2L;
10228 pOutputSamples[i*8+5] = (drflac_int16)temp2R;
10229 pOutputSamples[i*8+6] = (drflac_int16)temp3L;
10230 pOutputSamples[i*8+7] = (drflac_int16)temp3R;
10231 }
10232 } else {
10233 for (i = 0; i < frameCount4; ++i) {
10234 drflac_uint32 temp0L;
10235 drflac_uint32 temp1L;
10236 drflac_uint32 temp2L;
10237 drflac_uint32 temp3L;
10238 drflac_uint32 temp0R;
10239 drflac_uint32 temp1R;
10240 drflac_uint32 temp2R;
10241 drflac_uint32 temp3R;
10242
10243 drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
10244 drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
10245 drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
10246 drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
10247
10248 drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
10249 drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
10250 drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
10251 drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
10252
10253 mid0 = (mid0 << 1) | (side0 & 0x01);
10254 mid1 = (mid1 << 1) | (side1 & 0x01);
10255 mid2 = (mid2 << 1) | (side2 & 0x01);
10256 mid3 = (mid3 << 1) | (side3 & 0x01);
10257
10258 temp0L = ((drflac_int32)(mid0 + side0) >> 1);
10259 temp1L = ((drflac_int32)(mid1 + side1) >> 1);
10260 temp2L = ((drflac_int32)(mid2 + side2) >> 1);
10261 temp3L = ((drflac_int32)(mid3 + side3) >> 1);
10262
10263 temp0R = ((drflac_int32)(mid0 - side0) >> 1);
10264 temp1R = ((drflac_int32)(mid1 - side1) >> 1);
10265 temp2R = ((drflac_int32)(mid2 - side2) >> 1);
10266 temp3R = ((drflac_int32)(mid3 - side3) >> 1);
10267
10268 temp0L >>= 16;
10269 temp1L >>= 16;
10270 temp2L >>= 16;
10271 temp3L >>= 16;
10272
10273 temp0R >>= 16;
10274 temp1R >>= 16;
10275 temp2R >>= 16;
10276 temp3R >>= 16;
10277
10278 pOutputSamples[i*8+0] = (drflac_int16)temp0L;
10279 pOutputSamples[i*8+1] = (drflac_int16)temp0R;
10280 pOutputSamples[i*8+2] = (drflac_int16)temp1L;
10281 pOutputSamples[i*8+3] = (drflac_int16)temp1R;
10282 pOutputSamples[i*8+4] = (drflac_int16)temp2L;
10283 pOutputSamples[i*8+5] = (drflac_int16)temp2R;
10284 pOutputSamples[i*8+6] = (drflac_int16)temp3L;
10285 pOutputSamples[i*8+7] = (drflac_int16)temp3R;
10286 }
10287 }
10288
10289 for (i = (frameCount4 << 2); i < frameCount; ++i) {
10290 drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
10291 drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
10292
10293 mid = (mid << 1) | (side & 0x01);
10294
10295 pOutputSamples[i*2+0] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample) >> 16);
10296 pOutputSamples[i*2+1] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample) >> 16);
10297 }
10298}
10299
10300#if defined(DRFLAC_SUPPORT_SSE2)
10301static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
10302{
10303 drflac_uint64 i;
10304 drflac_uint64 frameCount4 = frameCount >> 2;
10305 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
10306 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
10307 drflac_uint32 shift = unusedBitsPerSample;
10308
10309 DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
10310
10311 if (shift == 0) {
10312 for (i = 0; i < frameCount4; ++i) {
10313 __m128i mid;
10314 __m128i side;
10315 __m128i left;
10316 __m128i right;
10317
10318 mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
10319 side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
10320
10321 mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
10322
10323 left = _mm_srai_epi32(_mm_add_epi32(mid, side), 1);
10324 right = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1);
10325
10326 left = _mm_srai_epi32(left, 16);
10327 right = _mm_srai_epi32(right, 16);
10328
10329 _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right));
10330 }
10331
10332 for (i = (frameCount4 << 2); i < frameCount; ++i) {
10333 drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
10334 drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
10335
10336 mid = (mid << 1) | (side & 0x01);
10337
10338 pOutputSamples[i*2+0] = (drflac_int16)(((drflac_int32)(mid + side) >> 1) >> 16);
10339 pOutputSamples[i*2+1] = (drflac_int16)(((drflac_int32)(mid - side) >> 1) >> 16);
10340 }
10341 } else {
10342 shift -= 1;
10343 for (i = 0; i < frameCount4; ++i) {
10344 __m128i mid;
10345 __m128i side;
10346 __m128i left;
10347 __m128i right;
10348
10349 mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
10350 side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
10351
10352 mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
10353
10354 left = _mm_slli_epi32(_mm_add_epi32(mid, side), shift);
10355 right = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift);
10356
10357 left = _mm_srai_epi32(left, 16);
10358 right = _mm_srai_epi32(right, 16);
10359
10360 _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right));
10361 }
10362
10363 for (i = (frameCount4 << 2); i < frameCount; ++i) {
10364 drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
10365 drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
10366
10367 mid = (mid << 1) | (side & 0x01);
10368
10369 pOutputSamples[i*2+0] = (drflac_int16)(((mid + side) << shift) >> 16);
10370 pOutputSamples[i*2+1] = (drflac_int16)(((mid - side) << shift) >> 16);
10371 }
10372 }
10373}
10374#endif
10375
10376#if defined(DRFLAC_SUPPORT_NEON)
10377static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
10378{
10379 drflac_uint64 i;
10380 drflac_uint64 frameCount4 = frameCount >> 2;
10381 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
10382 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
10383 drflac_uint32 shift = unusedBitsPerSample;
10384 int32x4_t wbpsShift0_4; /* wbps = Wasted Bits Per Sample */
10385 int32x4_t wbpsShift1_4; /* wbps = Wasted Bits Per Sample */
10386
10387 DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
10388
10389 wbpsShift0_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
10390 wbpsShift1_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
10391
10392 if (shift == 0) {
10393 for (i = 0; i < frameCount4; ++i) {
10394 uint32x4_t mid;
10395 uint32x4_t side;
10396 int32x4_t left;
10397 int32x4_t right;
10398
10399 mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4);
10400 side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4);
10401
10402 mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1)));
10403
10404 left = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1);
10405 right = vshrq_n_s32(vreinterpretq_s32_u32(vsubq_u32(mid, side)), 1);
10406
10407 left = vshrq_n_s32(left, 16);
10408 right = vshrq_n_s32(right, 16);
10409
10410 drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right)));
10411 }
10412
10413 for (i = (frameCount4 << 2); i < frameCount; ++i) {
10414 drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
10415 drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
10416
10417 mid = (mid << 1) | (side & 0x01);
10418
10419 pOutputSamples[i*2+0] = (drflac_int16)(((drflac_int32)(mid + side) >> 1) >> 16);
10420 pOutputSamples[i*2+1] = (drflac_int16)(((drflac_int32)(mid - side) >> 1) >> 16);
10421 }
10422 } else {
10423 int32x4_t shift4;
10424
10425 shift -= 1;
10426 shift4 = vdupq_n_s32(shift);
10427
10428 for (i = 0; i < frameCount4; ++i) {
10429 uint32x4_t mid;
10430 uint32x4_t side;
10431 int32x4_t left;
10432 int32x4_t right;
10433
10434 mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4);
10435 side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4);
10436
10437 mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1)));
10438
10439 left = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4));
10440 right = vreinterpretq_s32_u32(vshlq_u32(vsubq_u32(mid, side), shift4));
10441
10442 left = vshrq_n_s32(left, 16);
10443 right = vshrq_n_s32(right, 16);
10444
10445 drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right)));
10446 }
10447
10448 for (i = (frameCount4 << 2); i < frameCount; ++i) {
10449 drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
10450 drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
10451
10452 mid = (mid << 1) | (side & 0x01);
10453
10454 pOutputSamples[i*2+0] = (drflac_int16)(((mid + side) << shift) >> 16);
10455 pOutputSamples[i*2+1] = (drflac_int16)(((mid - side) << shift) >> 16);
10456 }
10457 }
10458}
10459#endif
10460
10461static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
10462{
10463#if defined(DRFLAC_SUPPORT_SSE2)
10464 if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
10465 drflac_read_pcm_frames_s16__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
10466 } else
10467#elif defined(DRFLAC_SUPPORT_NEON)
10468 if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
10469 drflac_read_pcm_frames_s16__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
10470 } else
10471#endif
10472 {
10473 /* Scalar fallback. */
10474#if 0
10475 drflac_read_pcm_frames_s16__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
10476#else
10477 drflac_read_pcm_frames_s16__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
10478#endif
10479 }
10480}
10481
10482
10483#if 0
10484static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
10485{
10486 for (drflac_uint64 i = 0; i < frameCount; ++i) {
10487 pOutputSamples[i*2+0] = (drflac_int16)((drflac_int32)((drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample)) >> 16);
10488 pOutputSamples[i*2+1] = (drflac_int16)((drflac_int32)((drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample)) >> 16);
10489 }
10490}
10491#endif
10492
10493static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
10494{
10495 drflac_uint64 i;
10496 drflac_uint64 frameCount4 = frameCount >> 2;
10497 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
10498 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
10499 drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
10500 drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
10501
10502 for (i = 0; i < frameCount4; ++i) {
10503 drflac_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0;
10504 drflac_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0;
10505 drflac_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0;
10506 drflac_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0;
10507
10508 drflac_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1;
10509 drflac_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1;
10510 drflac_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1;
10511 drflac_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1;
10512
10513 tempL0 >>= 16;
10514 tempL1 >>= 16;
10515 tempL2 >>= 16;
10516 tempL3 >>= 16;
10517
10518 tempR0 >>= 16;
10519 tempR1 >>= 16;
10520 tempR2 >>= 16;
10521 tempR3 >>= 16;
10522
10523 pOutputSamples[i*8+0] = (drflac_int16)tempL0;
10524 pOutputSamples[i*8+1] = (drflac_int16)tempR0;
10525 pOutputSamples[i*8+2] = (drflac_int16)tempL1;
10526 pOutputSamples[i*8+3] = (drflac_int16)tempR1;
10527 pOutputSamples[i*8+4] = (drflac_int16)tempL2;
10528 pOutputSamples[i*8+5] = (drflac_int16)tempR2;
10529 pOutputSamples[i*8+6] = (drflac_int16)tempL3;
10530 pOutputSamples[i*8+7] = (drflac_int16)tempR3;
10531 }
10532
10533 for (i = (frameCount4 << 2); i < frameCount; ++i) {
10534 pOutputSamples[i*2+0] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16);
10535 pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16);
10536 }
10537}
10538
10539#if defined(DRFLAC_SUPPORT_SSE2)
10540static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
10541{
10542 drflac_uint64 i;
10543 drflac_uint64 frameCount4 = frameCount >> 2;
10544 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
10545 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
10546 drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
10547 drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
10548
10549 for (i = 0; i < frameCount4; ++i) {
10550 __m128i left = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
10551 __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
10552
10553 left = _mm_srai_epi32(left, 16);
10554 right = _mm_srai_epi32(right, 16);
10555
10556 /* At this point we have results. We can now pack and interleave these into a single __m128i object and then store the in the output buffer. */
10557 _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right));
10558 }
10559
10560 for (i = (frameCount4 << 2); i < frameCount; ++i) {
10561 pOutputSamples[i*2+0] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16);
10562 pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16);
10563 }
10564}
10565#endif
10566
10567#if defined(DRFLAC_SUPPORT_NEON)
10568static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
10569{
10570 drflac_uint64 i;
10571 drflac_uint64 frameCount4 = frameCount >> 2;
10572 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
10573 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
10574 drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
10575 drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
10576
10577 int32x4_t shift0_4 = vdupq_n_s32(shift0);
10578 int32x4_t shift1_4 = vdupq_n_s32(shift1);
10579
10580 for (i = 0; i < frameCount4; ++i) {
10581 int32x4_t left;
10582 int32x4_t right;
10583
10584 left = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4));
10585 right = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4));
10586
10587 left = vshrq_n_s32(left, 16);
10588 right = vshrq_n_s32(right, 16);
10589
10590 drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right)));
10591 }
10592
10593 for (i = (frameCount4 << 2); i < frameCount; ++i) {
10594 pOutputSamples[i*2+0] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16);
10595 pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16);
10596 }
10597}
10598#endif
10599
10600static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
10601{
10602#if defined(DRFLAC_SUPPORT_SSE2)
10603 if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
10604 drflac_read_pcm_frames_s16__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
10605 } else
10606#elif defined(DRFLAC_SUPPORT_NEON)
10607 if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
10608 drflac_read_pcm_frames_s16__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
10609 } else
10610#endif
10611 {
10612 /* Scalar fallback. */
10613#if 0
10614 drflac_read_pcm_frames_s16__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
10615#else
10616 drflac_read_pcm_frames_s16__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
10617#endif
10618 }
10619}
10620
10621DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s16(drflac* pFlac, drflac_uint64 framesToRead, drflac_int16* pBufferOut)
10622{
10623 drflac_uint64 framesRead;
10624 drflac_uint32 unusedBitsPerSample;
10625
10626 if (pFlac == NULL || framesToRead == 0) {
10627 return 0;
10628 }
10629
10630 if (pBufferOut == NULL) {
10631 return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead);
10632 }
10633
10634 DRFLAC_ASSERT(pFlac->bitsPerSample <= 32);
10635 unusedBitsPerSample = 32 - pFlac->bitsPerSample;
10636
10637 framesRead = 0;
10638 while (framesToRead > 0) {
10639 /* If we've run out of samples in this frame, go to the next. */
10640 if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
10641 if (!drflac__read_and_decode_next_flac_frame(pFlac)) {
10642 break; /* Couldn't read the next frame, so just break from the loop and return. */
10643 }
10644 } else {
10645 unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment);
10646 drflac_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining;
10647 drflac_uint64 frameCountThisIteration = framesToRead;
10648
10649 if (frameCountThisIteration > pFlac->currentFLACFrame.pcmFramesRemaining) {
10650 frameCountThisIteration = pFlac->currentFLACFrame.pcmFramesRemaining;
10651 }
10652
10653 if (channelCount == 2) {
10654 const drflac_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame;
10655 const drflac_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame;
10656
10657 switch (pFlac->currentFLACFrame.header.channelAssignment)
10658 {
10659 case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE:
10660 {
10661 drflac_read_pcm_frames_s16__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
10662 } break;
10663
10664 case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE:
10665 {
10666 drflac_read_pcm_frames_s16__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
10667 } break;
10668
10669 case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE:
10670 {
10671 drflac_read_pcm_frames_s16__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
10672 } break;
10673
10674 case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT:
10675 default:
10676 {
10677 drflac_read_pcm_frames_s16__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
10678 } break;
10679 }
10680 } else {
10681 /* Generic interleaving. */
10682 drflac_uint64 i;
10683 for (i = 0; i < frameCountThisIteration; ++i) {
10684 unsigned int j;
10685 for (j = 0; j < channelCount; ++j) {
10686 drflac_int32 sampleS32 = (drflac_int32)((drflac_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample));
10687 pBufferOut[(i*channelCount)+j] = (drflac_int16)(sampleS32 >> 16);
10688 }
10689 }
10690 }
10691
10692 framesRead += frameCountThisIteration;
10693 pBufferOut += frameCountThisIteration * channelCount;
10694 framesToRead -= frameCountThisIteration;
10695 pFlac->currentPCMFrame += frameCountThisIteration;
10696 pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)frameCountThisIteration;
10697 }
10698 }
10699
10700 return framesRead;
10701}
10702
10703
10704#if 0
10705static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
10706{
10707 drflac_uint64 i;
10708 for (i = 0; i < frameCount; ++i) {
10709 drflac_uint32 left = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
10710 drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
10711 drflac_uint32 right = left - side;
10712
10713 pOutputSamples[i*2+0] = (float)((drflac_int32)left / 2147483648.0);
10714 pOutputSamples[i*2+1] = (float)((drflac_int32)right / 2147483648.0);
10715 }
10716}
10717#endif
10718
10719static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
10720{
10721 drflac_uint64 i;
10722 drflac_uint64 frameCount4 = frameCount >> 2;
10723 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
10724 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
10725 drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
10726 drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
10727
10728 float factor = 1 / 2147483648.0;
10729
10730 for (i = 0; i < frameCount4; ++i) {
10731 drflac_uint32 left0 = pInputSamples0U32[i*4+0] << shift0;
10732 drflac_uint32 left1 = pInputSamples0U32[i*4+1] << shift0;
10733 drflac_uint32 left2 = pInputSamples0U32[i*4+2] << shift0;
10734 drflac_uint32 left3 = pInputSamples0U32[i*4+3] << shift0;
10735
10736 drflac_uint32 side0 = pInputSamples1U32[i*4+0] << shift1;
10737 drflac_uint32 side1 = pInputSamples1U32[i*4+1] << shift1;
10738 drflac_uint32 side2 = pInputSamples1U32[i*4+2] << shift1;
10739 drflac_uint32 side3 = pInputSamples1U32[i*4+3] << shift1;
10740
10741 drflac_uint32 right0 = left0 - side0;
10742 drflac_uint32 right1 = left1 - side1;
10743 drflac_uint32 right2 = left2 - side2;
10744 drflac_uint32 right3 = left3 - side3;
10745
10746 pOutputSamples[i*8+0] = (drflac_int32)left0 * factor;
10747 pOutputSamples[i*8+1] = (drflac_int32)right0 * factor;
10748 pOutputSamples[i*8+2] = (drflac_int32)left1 * factor;
10749 pOutputSamples[i*8+3] = (drflac_int32)right1 * factor;
10750 pOutputSamples[i*8+4] = (drflac_int32)left2 * factor;
10751 pOutputSamples[i*8+5] = (drflac_int32)right2 * factor;
10752 pOutputSamples[i*8+6] = (drflac_int32)left3 * factor;
10753 pOutputSamples[i*8+7] = (drflac_int32)right3 * factor;
10754 }
10755
10756 for (i = (frameCount4 << 2); i < frameCount; ++i) {
10757 drflac_uint32 left = pInputSamples0U32[i] << shift0;
10758 drflac_uint32 side = pInputSamples1U32[i] << shift1;
10759 drflac_uint32 right = left - side;
10760
10761 pOutputSamples[i*2+0] = (drflac_int32)left * factor;
10762 pOutputSamples[i*2+1] = (drflac_int32)right * factor;
10763 }
10764}
10765
10766#if defined(DRFLAC_SUPPORT_SSE2)
10767static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
10768{
10769 drflac_uint64 i;
10770 drflac_uint64 frameCount4 = frameCount >> 2;
10771 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
10772 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
10773 drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
10774 drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
10775 __m128 factor;
10776
10777 DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
10778
10779 factor = _mm_set1_ps(1.0f / 8388608.0f);
10780
10781 for (i = 0; i < frameCount4; ++i) {
10782 __m128i left = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
10783 __m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
10784 __m128i right = _mm_sub_epi32(left, side);
10785 __m128 leftf = _mm_mul_ps(_mm_cvtepi32_ps(left), factor);
10786 __m128 rightf = _mm_mul_ps(_mm_cvtepi32_ps(right), factor);
10787
10788 _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf));
10789 _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf));
10790 }
10791
10792 for (i = (frameCount4 << 2); i < frameCount; ++i) {
10793 drflac_uint32 left = pInputSamples0U32[i] << shift0;
10794 drflac_uint32 side = pInputSamples1U32[i] << shift1;
10795 drflac_uint32 right = left - side;
10796
10797 pOutputSamples[i*2+0] = (drflac_int32)left / 8388608.0f;
10798 pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f;
10799 }
10800}
10801#endif
10802
10803#if defined(DRFLAC_SUPPORT_NEON)
10804static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
10805{
10806 drflac_uint64 i;
10807 drflac_uint64 frameCount4 = frameCount >> 2;
10808 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
10809 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
10810 drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
10811 drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
10812 float32x4_t factor4;
10813 int32x4_t shift0_4;
10814 int32x4_t shift1_4;
10815
10816 DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
10817
10818 factor4 = vdupq_n_f32(1.0f / 8388608.0f);
10819 shift0_4 = vdupq_n_s32(shift0);
10820 shift1_4 = vdupq_n_s32(shift1);
10821
10822 for (i = 0; i < frameCount4; ++i) {
10823 uint32x4_t left;
10824 uint32x4_t side;
10825 uint32x4_t right;
10826 float32x4_t leftf;
10827 float32x4_t rightf;
10828
10829 left = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
10830 side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
10831 right = vsubq_u32(left, side);
10832 leftf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(left)), factor4);
10833 rightf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(right)), factor4);
10834
10835 drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf));
10836 }
10837
10838 for (i = (frameCount4 << 2); i < frameCount; ++i) {
10839 drflac_uint32 left = pInputSamples0U32[i] << shift0;
10840 drflac_uint32 side = pInputSamples1U32[i] << shift1;
10841 drflac_uint32 right = left - side;
10842
10843 pOutputSamples[i*2+0] = (drflac_int32)left / 8388608.0f;
10844 pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f;
10845 }
10846}
10847#endif
10848
10849static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
10850{
10851#if defined(DRFLAC_SUPPORT_SSE2)
10852 if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
10853 drflac_read_pcm_frames_f32__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
10854 } else
10855#elif defined(DRFLAC_SUPPORT_NEON)
10856 if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
10857 drflac_read_pcm_frames_f32__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
10858 } else
10859#endif
10860 {
10861 /* Scalar fallback. */
10862#if 0
10863 drflac_read_pcm_frames_f32__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
10864#else
10865 drflac_read_pcm_frames_f32__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
10866#endif
10867 }
10868}
10869
10870
10871#if 0
10872static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
10873{
10874 drflac_uint64 i;
10875 for (i = 0; i < frameCount; ++i) {
10876 drflac_uint32 side = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
10877 drflac_uint32 right = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
10878 drflac_uint32 left = right + side;
10879
10880 pOutputSamples[i*2+0] = (float)((drflac_int32)left / 2147483648.0);
10881 pOutputSamples[i*2+1] = (float)((drflac_int32)right / 2147483648.0);
10882 }
10883}
10884#endif
10885
10886static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
10887{
10888 drflac_uint64 i;
10889 drflac_uint64 frameCount4 = frameCount >> 2;
10890 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
10891 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
10892 drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
10893 drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
10894 float factor = 1 / 2147483648.0;
10895
10896 for (i = 0; i < frameCount4; ++i) {
10897 drflac_uint32 side0 = pInputSamples0U32[i*4+0] << shift0;
10898 drflac_uint32 side1 = pInputSamples0U32[i*4+1] << shift0;
10899 drflac_uint32 side2 = pInputSamples0U32[i*4+2] << shift0;
10900 drflac_uint32 side3 = pInputSamples0U32[i*4+3] << shift0;
10901
10902 drflac_uint32 right0 = pInputSamples1U32[i*4+0] << shift1;
10903 drflac_uint32 right1 = pInputSamples1U32[i*4+1] << shift1;
10904 drflac_uint32 right2 = pInputSamples1U32[i*4+2] << shift1;
10905 drflac_uint32 right3 = pInputSamples1U32[i*4+3] << shift1;
10906
10907 drflac_uint32 left0 = right0 + side0;
10908 drflac_uint32 left1 = right1 + side1;
10909 drflac_uint32 left2 = right2 + side2;
10910 drflac_uint32 left3 = right3 + side3;
10911
10912 pOutputSamples[i*8+0] = (drflac_int32)left0 * factor;
10913 pOutputSamples[i*8+1] = (drflac_int32)right0 * factor;
10914 pOutputSamples[i*8+2] = (drflac_int32)left1 * factor;
10915 pOutputSamples[i*8+3] = (drflac_int32)right1 * factor;
10916 pOutputSamples[i*8+4] = (drflac_int32)left2 * factor;
10917 pOutputSamples[i*8+5] = (drflac_int32)right2 * factor;
10918 pOutputSamples[i*8+6] = (drflac_int32)left3 * factor;
10919 pOutputSamples[i*8+7] = (drflac_int32)right3 * factor;
10920 }
10921
10922 for (i = (frameCount4 << 2); i < frameCount; ++i) {
10923 drflac_uint32 side = pInputSamples0U32[i] << shift0;
10924 drflac_uint32 right = pInputSamples1U32[i] << shift1;
10925 drflac_uint32 left = right + side;
10926
10927 pOutputSamples[i*2+0] = (drflac_int32)left * factor;
10928 pOutputSamples[i*2+1] = (drflac_int32)right * factor;
10929 }
10930}
10931
10932#if defined(DRFLAC_SUPPORT_SSE2)
10933static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
10934{
10935 drflac_uint64 i;
10936 drflac_uint64 frameCount4 = frameCount >> 2;
10937 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
10938 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
10939 drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
10940 drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
10941 __m128 factor;
10942
10943 DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
10944
10945 factor = _mm_set1_ps(1.0f / 8388608.0f);
10946
10947 for (i = 0; i < frameCount4; ++i) {
10948 __m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
10949 __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
10950 __m128i left = _mm_add_epi32(right, side);
10951 __m128 leftf = _mm_mul_ps(_mm_cvtepi32_ps(left), factor);
10952 __m128 rightf = _mm_mul_ps(_mm_cvtepi32_ps(right), factor);
10953
10954 _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf));
10955 _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf));
10956 }
10957
10958 for (i = (frameCount4 << 2); i < frameCount; ++i) {
10959 drflac_uint32 side = pInputSamples0U32[i] << shift0;
10960 drflac_uint32 right = pInputSamples1U32[i] << shift1;
10961 drflac_uint32 left = right + side;
10962
10963 pOutputSamples[i*2+0] = (drflac_int32)left / 8388608.0f;
10964 pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f;
10965 }
10966}
10967#endif
10968
10969#if defined(DRFLAC_SUPPORT_NEON)
10970static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
10971{
10972 drflac_uint64 i;
10973 drflac_uint64 frameCount4 = frameCount >> 2;
10974 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
10975 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
10976 drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
10977 drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
10978 float32x4_t factor4;
10979 int32x4_t shift0_4;
10980 int32x4_t shift1_4;
10981
10982 DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
10983
10984 factor4 = vdupq_n_f32(1.0f / 8388608.0f);
10985 shift0_4 = vdupq_n_s32(shift0);
10986 shift1_4 = vdupq_n_s32(shift1);
10987
10988 for (i = 0; i < frameCount4; ++i) {
10989 uint32x4_t side;
10990 uint32x4_t right;
10991 uint32x4_t left;
10992 float32x4_t leftf;
10993 float32x4_t rightf;
10994
10995 side = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
10996 right = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
10997 left = vaddq_u32(right, side);
10998 leftf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(left)), factor4);
10999 rightf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(right)), factor4);
11000
11001 drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf));
11002 }
11003
11004 for (i = (frameCount4 << 2); i < frameCount; ++i) {
11005 drflac_uint32 side = pInputSamples0U32[i] << shift0;
11006 drflac_uint32 right = pInputSamples1U32[i] << shift1;
11007 drflac_uint32 left = right + side;
11008
11009 pOutputSamples[i*2+0] = (drflac_int32)left / 8388608.0f;
11010 pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f;
11011 }
11012}
11013#endif
11014
11015static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
11016{
11017#if defined(DRFLAC_SUPPORT_SSE2)
11018 if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
11019 drflac_read_pcm_frames_f32__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
11020 } else
11021#elif defined(DRFLAC_SUPPORT_NEON)
11022 if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
11023 drflac_read_pcm_frames_f32__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
11024 } else
11025#endif
11026 {
11027 /* Scalar fallback. */
11028#if 0
11029 drflac_read_pcm_frames_f32__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
11030#else
11031 drflac_read_pcm_frames_f32__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
11032#endif
11033 }
11034}
11035
11036
11037#if 0
11038static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
11039{
11040 for (drflac_uint64 i = 0; i < frameCount; ++i) {
11041 drflac_uint32 mid = (drflac_uint32)pInputSamples0[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
11042 drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
11043
11044 mid = (mid << 1) | (side & 0x01);
11045
11046 pOutputSamples[i*2+0] = (float)((((drflac_int32)(mid + side) >> 1) << (unusedBitsPerSample)) / 2147483648.0);
11047 pOutputSamples[i*2+1] = (float)((((drflac_int32)(mid - side) >> 1) << (unusedBitsPerSample)) / 2147483648.0);
11048 }
11049}
11050#endif
11051
11052static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
11053{
11054 drflac_uint64 i;
11055 drflac_uint64 frameCount4 = frameCount >> 2;
11056 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
11057 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
11058 drflac_uint32 shift = unusedBitsPerSample;
11059 float factor = 1 / 2147483648.0;
11060
11061 if (shift > 0) {
11062 shift -= 1;
11063 for (i = 0; i < frameCount4; ++i) {
11064 drflac_uint32 temp0L;
11065 drflac_uint32 temp1L;
11066 drflac_uint32 temp2L;
11067 drflac_uint32 temp3L;
11068 drflac_uint32 temp0R;
11069 drflac_uint32 temp1R;
11070 drflac_uint32 temp2R;
11071 drflac_uint32 temp3R;
11072
11073 drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
11074 drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
11075 drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
11076 drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
11077
11078 drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
11079 drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
11080 drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
11081 drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
11082
11083 mid0 = (mid0 << 1) | (side0 & 0x01);
11084 mid1 = (mid1 << 1) | (side1 & 0x01);
11085 mid2 = (mid2 << 1) | (side2 & 0x01);
11086 mid3 = (mid3 << 1) | (side3 & 0x01);
11087
11088 temp0L = (mid0 + side0) << shift;
11089 temp1L = (mid1 + side1) << shift;
11090 temp2L = (mid2 + side2) << shift;
11091 temp3L = (mid3 + side3) << shift;
11092
11093 temp0R = (mid0 - side0) << shift;
11094 temp1R = (mid1 - side1) << shift;
11095 temp2R = (mid2 - side2) << shift;
11096 temp3R = (mid3 - side3) << shift;
11097
11098 pOutputSamples[i*8+0] = (drflac_int32)temp0L * factor;
11099 pOutputSamples[i*8+1] = (drflac_int32)temp0R * factor;
11100 pOutputSamples[i*8+2] = (drflac_int32)temp1L * factor;
11101 pOutputSamples[i*8+3] = (drflac_int32)temp1R * factor;
11102 pOutputSamples[i*8+4] = (drflac_int32)temp2L * factor;
11103 pOutputSamples[i*8+5] = (drflac_int32)temp2R * factor;
11104 pOutputSamples[i*8+6] = (drflac_int32)temp3L * factor;
11105 pOutputSamples[i*8+7] = (drflac_int32)temp3R * factor;
11106 }
11107 } else {
11108 for (i = 0; i < frameCount4; ++i) {
11109 drflac_uint32 temp0L;
11110 drflac_uint32 temp1L;
11111 drflac_uint32 temp2L;
11112 drflac_uint32 temp3L;
11113 drflac_uint32 temp0R;
11114 drflac_uint32 temp1R;
11115 drflac_uint32 temp2R;
11116 drflac_uint32 temp3R;
11117
11118 drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
11119 drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
11120 drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
11121 drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
11122
11123 drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
11124 drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
11125 drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
11126 drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
11127
11128 mid0 = (mid0 << 1) | (side0 & 0x01);
11129 mid1 = (mid1 << 1) | (side1 & 0x01);
11130 mid2 = (mid2 << 1) | (side2 & 0x01);
11131 mid3 = (mid3 << 1) | (side3 & 0x01);
11132
11133 temp0L = (drflac_uint32)((drflac_int32)(mid0 + side0) >> 1);
11134 temp1L = (drflac_uint32)((drflac_int32)(mid1 + side1) >> 1);
11135 temp2L = (drflac_uint32)((drflac_int32)(mid2 + side2) >> 1);
11136 temp3L = (drflac_uint32)((drflac_int32)(mid3 + side3) >> 1);
11137
11138 temp0R = (drflac_uint32)((drflac_int32)(mid0 - side0) >> 1);
11139 temp1R = (drflac_uint32)((drflac_int32)(mid1 - side1) >> 1);
11140 temp2R = (drflac_uint32)((drflac_int32)(mid2 - side2) >> 1);
11141 temp3R = (drflac_uint32)((drflac_int32)(mid3 - side3) >> 1);
11142
11143 pOutputSamples[i*8+0] = (drflac_int32)temp0L * factor;
11144 pOutputSamples[i*8+1] = (drflac_int32)temp0R * factor;
11145 pOutputSamples[i*8+2] = (drflac_int32)temp1L * factor;
11146 pOutputSamples[i*8+3] = (drflac_int32)temp1R * factor;
11147 pOutputSamples[i*8+4] = (drflac_int32)temp2L * factor;
11148 pOutputSamples[i*8+5] = (drflac_int32)temp2R * factor;
11149 pOutputSamples[i*8+6] = (drflac_int32)temp3L * factor;
11150 pOutputSamples[i*8+7] = (drflac_int32)temp3R * factor;
11151 }
11152 }
11153
11154 for (i = (frameCount4 << 2); i < frameCount; ++i) {
11155 drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
11156 drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
11157
11158 mid = (mid << 1) | (side & 0x01);
11159
11160 pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample) * factor;
11161 pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample) * factor;
11162 }
11163}
11164
11165#if defined(DRFLAC_SUPPORT_SSE2)
11166static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
11167{
11168 drflac_uint64 i;
11169 drflac_uint64 frameCount4 = frameCount >> 2;
11170 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
11171 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
11172 drflac_uint32 shift = unusedBitsPerSample - 8;
11173 float factor;
11174 __m128 factor128;
11175
11176 DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
11177
11178 factor = 1.0f / 8388608.0f;
11179 factor128 = _mm_set1_ps(factor);
11180
11181 if (shift == 0) {
11182 for (i = 0; i < frameCount4; ++i) {
11183 __m128i mid;
11184 __m128i side;
11185 __m128i tempL;
11186 __m128i tempR;
11187 __m128 leftf;
11188 __m128 rightf;
11189
11190 mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
11191 side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
11192
11193 mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
11194
11195 tempL = _mm_srai_epi32(_mm_add_epi32(mid, side), 1);
11196 tempR = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1);
11197
11198 leftf = _mm_mul_ps(_mm_cvtepi32_ps(tempL), factor128);
11199 rightf = _mm_mul_ps(_mm_cvtepi32_ps(tempR), factor128);
11200
11201 _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf));
11202 _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf));
11203 }
11204
11205 for (i = (frameCount4 << 2); i < frameCount; ++i) {
11206 drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
11207 drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
11208
11209 mid = (mid << 1) | (side & 0x01);
11210
11211 pOutputSamples[i*2+0] = ((drflac_int32)(mid + side) >> 1) * factor;
11212 pOutputSamples[i*2+1] = ((drflac_int32)(mid - side) >> 1) * factor;
11213 }
11214 } else {
11215 shift -= 1;
11216 for (i = 0; i < frameCount4; ++i) {
11217 __m128i mid;
11218 __m128i side;
11219 __m128i tempL;
11220 __m128i tempR;
11221 __m128 leftf;
11222 __m128 rightf;
11223
11224 mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
11225 side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
11226
11227 mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
11228
11229 tempL = _mm_slli_epi32(_mm_add_epi32(mid, side), shift);
11230 tempR = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift);
11231
11232 leftf = _mm_mul_ps(_mm_cvtepi32_ps(tempL), factor128);
11233 rightf = _mm_mul_ps(_mm_cvtepi32_ps(tempR), factor128);
11234
11235 _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf));
11236 _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf));
11237 }
11238
11239 for (i = (frameCount4 << 2); i < frameCount; ++i) {
11240 drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
11241 drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
11242
11243 mid = (mid << 1) | (side & 0x01);
11244
11245 pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift) * factor;
11246 pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift) * factor;
11247 }
11248 }
11249}
11250#endif
11251
11252#if defined(DRFLAC_SUPPORT_NEON)
11253static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
11254{
11255 drflac_uint64 i;
11256 drflac_uint64 frameCount4 = frameCount >> 2;
11257 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
11258 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
11259 drflac_uint32 shift = unusedBitsPerSample - 8;
11260 float factor;
11261 float32x4_t factor4;
11262 int32x4_t shift4;
11263 int32x4_t wbps0_4; /* Wasted Bits Per Sample */
11264 int32x4_t wbps1_4; /* Wasted Bits Per Sample */
11265
11266 DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
11267
11268 factor = 1.0f / 8388608.0f;
11269 factor4 = vdupq_n_f32(factor);
11270 wbps0_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
11271 wbps1_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
11272
11273 if (shift == 0) {
11274 for (i = 0; i < frameCount4; ++i) {
11275 int32x4_t lefti;
11276 int32x4_t righti;
11277 float32x4_t leftf;
11278 float32x4_t rightf;
11279
11280 uint32x4_t mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbps0_4);
11281 uint32x4_t side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbps1_4);
11282
11283 mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1)));
11284
11285 lefti = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1);
11286 righti = vshrq_n_s32(vreinterpretq_s32_u32(vsubq_u32(mid, side)), 1);
11287
11288 leftf = vmulq_f32(vcvtq_f32_s32(lefti), factor4);
11289 rightf = vmulq_f32(vcvtq_f32_s32(righti), factor4);
11290
11291 drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf));
11292 }
11293
11294 for (i = (frameCount4 << 2); i < frameCount; ++i) {
11295 drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
11296 drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
11297
11298 mid = (mid << 1) | (side & 0x01);
11299
11300 pOutputSamples[i*2+0] = ((drflac_int32)(mid + side) >> 1) * factor;
11301 pOutputSamples[i*2+1] = ((drflac_int32)(mid - side) >> 1) * factor;
11302 }
11303 } else {
11304 shift -= 1;
11305 shift4 = vdupq_n_s32(shift);
11306 for (i = 0; i < frameCount4; ++i) {
11307 uint32x4_t mid;
11308 uint32x4_t side;
11309 int32x4_t lefti;
11310 int32x4_t righti;
11311 float32x4_t leftf;
11312 float32x4_t rightf;
11313
11314 mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbps0_4);
11315 side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbps1_4);
11316
11317 mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1)));
11318
11319 lefti = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4));
11320 righti = vreinterpretq_s32_u32(vshlq_u32(vsubq_u32(mid, side), shift4));
11321
11322 leftf = vmulq_f32(vcvtq_f32_s32(lefti), factor4);
11323 rightf = vmulq_f32(vcvtq_f32_s32(righti), factor4);
11324
11325 drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf));
11326 }
11327
11328 for (i = (frameCount4 << 2); i < frameCount; ++i) {
11329 drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
11330 drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
11331
11332 mid = (mid << 1) | (side & 0x01);
11333
11334 pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift) * factor;
11335 pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift) * factor;
11336 }
11337 }
11338}
11339#endif
11340
11341static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
11342{
11343#if defined(DRFLAC_SUPPORT_SSE2)
11344 if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
11345 drflac_read_pcm_frames_f32__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
11346 } else
11347#elif defined(DRFLAC_SUPPORT_NEON)
11348 if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
11349 drflac_read_pcm_frames_f32__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
11350 } else
11351#endif
11352 {
11353 /* Scalar fallback. */
11354#if 0
11355 drflac_read_pcm_frames_f32__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
11356#else
11357 drflac_read_pcm_frames_f32__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
11358#endif
11359 }
11360}
11361
11362#if 0
11363static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
11364{
11365 for (drflac_uint64 i = 0; i < frameCount; ++i) {
11366 pOutputSamples[i*2+0] = (float)((drflac_int32)((drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample)) / 2147483648.0);
11367 pOutputSamples[i*2+1] = (float)((drflac_int32)((drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample)) / 2147483648.0);
11368 }
11369}
11370#endif
11371
11372static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
11373{
11374 drflac_uint64 i;
11375 drflac_uint64 frameCount4 = frameCount >> 2;
11376 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
11377 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
11378 drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
11379 drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
11380 float factor = 1 / 2147483648.0;
11381
11382 for (i = 0; i < frameCount4; ++i) {
11383 drflac_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0;
11384 drflac_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0;
11385 drflac_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0;
11386 drflac_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0;
11387
11388 drflac_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1;
11389 drflac_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1;
11390 drflac_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1;
11391 drflac_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1;
11392
11393 pOutputSamples[i*8+0] = (drflac_int32)tempL0 * factor;
11394 pOutputSamples[i*8+1] = (drflac_int32)tempR0 * factor;
11395 pOutputSamples[i*8+2] = (drflac_int32)tempL1 * factor;
11396 pOutputSamples[i*8+3] = (drflac_int32)tempR1 * factor;
11397 pOutputSamples[i*8+4] = (drflac_int32)tempL2 * factor;
11398 pOutputSamples[i*8+5] = (drflac_int32)tempR2 * factor;
11399 pOutputSamples[i*8+6] = (drflac_int32)tempL3 * factor;
11400 pOutputSamples[i*8+7] = (drflac_int32)tempR3 * factor;
11401 }
11402
11403 for (i = (frameCount4 << 2); i < frameCount; ++i) {
11404 pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor;
11405 pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor;
11406 }
11407}
11408
11409#if defined(DRFLAC_SUPPORT_SSE2)
11410static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
11411{
11412 drflac_uint64 i;
11413 drflac_uint64 frameCount4 = frameCount >> 2;
11414 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
11415 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
11416 drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
11417 drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
11418
11419 float factor = 1.0f / 8388608.0f;
11420 __m128 factor128 = _mm_set1_ps(factor);
11421
11422 for (i = 0; i < frameCount4; ++i) {
11423 __m128i lefti;
11424 __m128i righti;
11425 __m128 leftf;
11426 __m128 rightf;
11427
11428 lefti = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
11429 righti = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
11430
11431 leftf = _mm_mul_ps(_mm_cvtepi32_ps(lefti), factor128);
11432 rightf = _mm_mul_ps(_mm_cvtepi32_ps(righti), factor128);
11433
11434 _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf));
11435 _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf));
11436 }
11437
11438 for (i = (frameCount4 << 2); i < frameCount; ++i) {
11439 pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor;
11440 pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor;
11441 }
11442}
11443#endif
11444
11445#if defined(DRFLAC_SUPPORT_NEON)
11446static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
11447{
11448 drflac_uint64 i;
11449 drflac_uint64 frameCount4 = frameCount >> 2;
11450 const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
11451 const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
11452 drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
11453 drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
11454
11455 float factor = 1.0f / 8388608.0f;
11456 float32x4_t factor4 = vdupq_n_f32(factor);
11457 int32x4_t shift0_4 = vdupq_n_s32(shift0);
11458 int32x4_t shift1_4 = vdupq_n_s32(shift1);
11459
11460 for (i = 0; i < frameCount4; ++i) {
11461 int32x4_t lefti;
11462 int32x4_t righti;
11463 float32x4_t leftf;
11464 float32x4_t rightf;
11465
11466 lefti = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4));
11467 righti = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4));
11468
11469 leftf = vmulq_f32(vcvtq_f32_s32(lefti), factor4);
11470 rightf = vmulq_f32(vcvtq_f32_s32(righti), factor4);
11471
11472 drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf));
11473 }
11474
11475 for (i = (frameCount4 << 2); i < frameCount; ++i) {
11476 pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor;
11477 pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor;
11478 }
11479}
11480#endif
11481
11482static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
11483{
11484#if defined(DRFLAC_SUPPORT_SSE2)
11485 if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
11486 drflac_read_pcm_frames_f32__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
11487 } else
11488#elif defined(DRFLAC_SUPPORT_NEON)
11489 if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
11490 drflac_read_pcm_frames_f32__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
11491 } else
11492#endif
11493 {
11494 /* Scalar fallback. */
11495#if 0
11496 drflac_read_pcm_frames_f32__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
11497#else
11498 drflac_read_pcm_frames_f32__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
11499#endif
11500 }
11501}
11502
11503DRFLAC_API drflac_uint64 drflac_read_pcm_frames_f32(drflac* pFlac, drflac_uint64 framesToRead, float* pBufferOut)
11504{
11505 drflac_uint64 framesRead;
11506 drflac_uint32 unusedBitsPerSample;
11507
11508 if (pFlac == NULL || framesToRead == 0) {
11509 return 0;
11510 }
11511
11512 if (pBufferOut == NULL) {
11513 return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead);
11514 }
11515
11516 DRFLAC_ASSERT(pFlac->bitsPerSample <= 32);
11517 unusedBitsPerSample = 32 - pFlac->bitsPerSample;
11518
11519 framesRead = 0;
11520 while (framesToRead > 0) {
11521 /* If we've run out of samples in this frame, go to the next. */
11522 if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
11523 if (!drflac__read_and_decode_next_flac_frame(pFlac)) {
11524 break; /* Couldn't read the next frame, so just break from the loop and return. */
11525 }
11526 } else {
11527 unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment);
11528 drflac_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining;
11529 drflac_uint64 frameCountThisIteration = framesToRead;
11530
11531 if (frameCountThisIteration > pFlac->currentFLACFrame.pcmFramesRemaining) {
11532 frameCountThisIteration = pFlac->currentFLACFrame.pcmFramesRemaining;
11533 }
11534
11535 if (channelCount == 2) {
11536 const drflac_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame;
11537 const drflac_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame;
11538
11539 switch (pFlac->currentFLACFrame.header.channelAssignment)
11540 {
11541 case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE:
11542 {
11543 drflac_read_pcm_frames_f32__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
11544 } break;
11545
11546 case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE:
11547 {
11548 drflac_read_pcm_frames_f32__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
11549 } break;
11550
11551 case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE:
11552 {
11553 drflac_read_pcm_frames_f32__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
11554 } break;
11555
11556 case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT:
11557 default:
11558 {
11559 drflac_read_pcm_frames_f32__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
11560 } break;
11561 }
11562 } else {
11563 /* Generic interleaving. */
11564 drflac_uint64 i;
11565 for (i = 0; i < frameCountThisIteration; ++i) {
11566 unsigned int j;
11567 for (j = 0; j < channelCount; ++j) {
11568 drflac_int32 sampleS32 = (drflac_int32)((drflac_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample));
11569 pBufferOut[(i*channelCount)+j] = (float)(sampleS32 / 2147483648.0);
11570 }
11571 }
11572 }
11573
11574 framesRead += frameCountThisIteration;
11575 pBufferOut += frameCountThisIteration * channelCount;
11576 framesToRead -= frameCountThisIteration;
11577 pFlac->currentPCMFrame += frameCountThisIteration;
11578 pFlac->currentFLACFrame.pcmFramesRemaining -= (unsigned int)frameCountThisIteration;
11579 }
11580 }
11581
11582 return framesRead;
11583}
11584
11585
11586DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex)
11587{
11588 if (pFlac == NULL) {
11589 return DRFLAC_FALSE;
11590 }
11591
11592 /* Don't do anything if we're already on the seek point. */
11593 if (pFlac->currentPCMFrame == pcmFrameIndex) {
11594 return DRFLAC_TRUE;
11595 }
11596
11597 /*
11598 If we don't know where the first frame begins then we can't seek. This will happen when the STREAMINFO block was not present
11599 when the decoder was opened.
11600 */
11601 if (pFlac->firstFLACFramePosInBytes == 0) {
11602 return DRFLAC_FALSE;
11603 }
11604
11605 if (pcmFrameIndex == 0) {
11606 pFlac->currentPCMFrame = 0;
11607 return drflac__seek_to_first_frame(pFlac);
11608 } else {
11609 drflac_bool32 wasSuccessful = DRFLAC_FALSE;
11610 drflac_uint64 originalPCMFrame = pFlac->currentPCMFrame;
11611
11612 /* Clamp the sample to the end. */
11613 if (pcmFrameIndex > pFlac->totalPCMFrameCount) {
11614 pcmFrameIndex = pFlac->totalPCMFrameCount;
11615 }
11616
11617 /* If the target sample and the current sample are in the same frame we just move the position forward. */
11618 if (pcmFrameIndex > pFlac->currentPCMFrame) {
11619 /* Forward. */
11620 drflac_uint32 offset = (drflac_uint32)(pcmFrameIndex - pFlac->currentPCMFrame);
11621 if (pFlac->currentFLACFrame.pcmFramesRemaining > offset) {
11622 pFlac->currentFLACFrame.pcmFramesRemaining -= offset;
11623 pFlac->currentPCMFrame = pcmFrameIndex;
11624 return DRFLAC_TRUE;
11625 }
11626 } else {
11627 /* Backward. */
11628 drflac_uint32 offsetAbs = (drflac_uint32)(pFlac->currentPCMFrame - pcmFrameIndex);
11629 drflac_uint32 currentFLACFramePCMFrameCount = pFlac->currentFLACFrame.header.blockSizeInPCMFrames;
11630 drflac_uint32 currentFLACFramePCMFramesConsumed = currentFLACFramePCMFrameCount - pFlac->currentFLACFrame.pcmFramesRemaining;
11631 if (currentFLACFramePCMFramesConsumed > offsetAbs) {
11632 pFlac->currentFLACFrame.pcmFramesRemaining += offsetAbs;
11633 pFlac->currentPCMFrame = pcmFrameIndex;
11634 return DRFLAC_TRUE;
11635 }
11636 }
11637
11638 /*
11639 Different techniques depending on encapsulation. Using the native FLAC seektable with Ogg encapsulation is a bit awkward so
11640 we'll instead use Ogg's natural seeking facility.
11641 */
11642#ifndef DR_FLAC_NO_OGG
11643 if (pFlac->container == drflac_container_ogg)
11644 {
11645 wasSuccessful = drflac_ogg__seek_to_pcm_frame(pFlac, pcmFrameIndex);
11646 }
11647 else
11648#endif
11649 {
11650 /* First try seeking via the seek table. If this fails, fall back to a brute force seek which is much slower. */
11651 if (/*!wasSuccessful && */!pFlac->_noSeekTableSeek) {
11652 wasSuccessful = drflac__seek_to_pcm_frame__seek_table(pFlac, pcmFrameIndex);
11653 }
11654
11655#if !defined(DR_FLAC_NO_CRC)
11656 /* Fall back to binary search if seek table seeking fails. This requires the length of the stream to be known. */
11657 if (!wasSuccessful && !pFlac->_noBinarySearchSeek && pFlac->totalPCMFrameCount > 0) {
11658 wasSuccessful = drflac__seek_to_pcm_frame__binary_search(pFlac, pcmFrameIndex);
11659 }
11660#endif
11661
11662 /* Fall back to brute force if all else fails. */
11663 if (!wasSuccessful && !pFlac->_noBruteForceSeek) {
11664 wasSuccessful = drflac__seek_to_pcm_frame__brute_force(pFlac, pcmFrameIndex);
11665 }
11666 }
11667
11668 if (wasSuccessful) {
11669 pFlac->currentPCMFrame = pcmFrameIndex;
11670 } else {
11671 /* Seek failed. Try putting the decoder back to it's original state. */
11672 if (drflac_seek_to_pcm_frame(pFlac, originalPCMFrame) == DRFLAC_FALSE) {
11673 /* Failed to seek back to the original PCM frame. Fall back to 0. */
11674 drflac_seek_to_pcm_frame(pFlac, 0);
11675 }
11676 }
11677
11678 return wasSuccessful;
11679 }
11680}
11681
11682
11683
11684/* High Level APIs */
11685
11686/* SIZE_MAX */
11687#if defined(SIZE_MAX)
11688 #define DRFLAC_SIZE_MAX SIZE_MAX
11689#else
11690 #if defined(DRFLAC_64BIT)
11691 #define DRFLAC_SIZE_MAX ((drflac_uint64)0xFFFFFFFFFFFFFFFF)
11692 #else
11693 #define DRFLAC_SIZE_MAX 0xFFFFFFFF
11694 #endif
11695#endif
11696/* End SIZE_MAX */
11697
11698
11699/* Using a macro as the definition of the drflac__full_decode_and_close_*() API family. Sue me. */
11700#define DRFLAC_DEFINE_FULL_READ_AND_CLOSE(extension, type) \
11701static type* drflac__full_read_and_close_ ## extension (drflac* pFlac, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut)\
11702{ \
11703 type* pSampleData = NULL; \
11704 drflac_uint64 totalPCMFrameCount; \
11705 \
11706 DRFLAC_ASSERT(pFlac != NULL); \
11707 \
11708 totalPCMFrameCount = pFlac->totalPCMFrameCount; \
11709 \
11710 if (totalPCMFrameCount == 0) { \
11711 type buffer[4096]; \
11712 drflac_uint64 pcmFramesRead; \
11713 size_t sampleDataBufferSize = sizeof(buffer); \
11714 \
11715 pSampleData = (type*)drflac__malloc_from_callbacks(sampleDataBufferSize, &pFlac->allocationCallbacks); \
11716 if (pSampleData == NULL) { \
11717 goto on_error; \
11718 } \
11719 \
11720 while ((pcmFramesRead = (drflac_uint64)drflac_read_pcm_frames_##extension(pFlac, sizeof(buffer)/sizeof(buffer[0])/pFlac->channels, buffer)) > 0) { \
11721 if (((totalPCMFrameCount + pcmFramesRead) * pFlac->channels * sizeof(type)) > sampleDataBufferSize) { \
11722 type* pNewSampleData; \
11723 size_t newSampleDataBufferSize; \
11724 \
11725 newSampleDataBufferSize = sampleDataBufferSize * 2; \
11726 pNewSampleData = (type*)drflac__realloc_from_callbacks(pSampleData, newSampleDataBufferSize, sampleDataBufferSize, &pFlac->allocationCallbacks); \
11727 if (pNewSampleData == NULL) { \
11728 drflac__free_from_callbacks(pSampleData, &pFlac->allocationCallbacks); \
11729 goto on_error; \
11730 } \
11731 \
11732 sampleDataBufferSize = newSampleDataBufferSize; \
11733 pSampleData = pNewSampleData; \
11734 } \
11735 \
11736 DRFLAC_COPY_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), buffer, (size_t)(pcmFramesRead*pFlac->channels*sizeof(type))); \
11737 totalPCMFrameCount += pcmFramesRead; \
11738 } \
11739 \
11740 /* At this point everything should be decoded, but we just want to fill the unused part buffer with silence - need to \
11741 protect those ears from random noise! */ \
11742 DRFLAC_ZERO_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), (size_t)(sampleDataBufferSize - totalPCMFrameCount*pFlac->channels*sizeof(type))); \
11743 } else { \
11744 drflac_uint64 dataSize = totalPCMFrameCount*pFlac->channels*sizeof(type); \
11745 if (dataSize > (drflac_uint64)DRFLAC_SIZE_MAX) { \
11746 goto on_error; /* The decoded data is too big. */ \
11747 } \
11748 \
11749 pSampleData = (type*)drflac__malloc_from_callbacks((size_t)dataSize, &pFlac->allocationCallbacks); /* <-- Safe cast as per the check above. */ \
11750 if (pSampleData == NULL) { \
11751 goto on_error; \
11752 } \
11753 \
11754 totalPCMFrameCount = drflac_read_pcm_frames_##extension(pFlac, pFlac->totalPCMFrameCount, pSampleData); \
11755 } \
11756 \
11757 if (sampleRateOut) *sampleRateOut = pFlac->sampleRate; \
11758 if (channelsOut) *channelsOut = pFlac->channels; \
11759 if (totalPCMFrameCountOut) *totalPCMFrameCountOut = totalPCMFrameCount; \
11760 \
11761 drflac_close(pFlac); \
11762 return pSampleData; \
11763 \
11764on_error: \
11765 drflac_close(pFlac); \
11766 return NULL; \
11767}
11768
11769DRFLAC_DEFINE_FULL_READ_AND_CLOSE(s32, drflac_int32)
11770DRFLAC_DEFINE_FULL_READ_AND_CLOSE(s16, drflac_int16)
11771DRFLAC_DEFINE_FULL_READ_AND_CLOSE(f32, float)
11772
11773DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
11774{
11775 drflac* pFlac;
11776
11777 if (channelsOut) {
11778 *channelsOut = 0;
11779 }
11780 if (sampleRateOut) {
11781 *sampleRateOut = 0;
11782 }
11783 if (totalPCMFrameCountOut) {
11784 *totalPCMFrameCountOut = 0;
11785 }
11786
11787 pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
11788 if (pFlac == NULL) {
11789 return NULL;
11790 }
11791
11792 return drflac__full_read_and_close_s32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
11793}
11794
11795DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
11796{
11797 drflac* pFlac;
11798
11799 if (channelsOut) {
11800 *channelsOut = 0;
11801 }
11802 if (sampleRateOut) {
11803 *sampleRateOut = 0;
11804 }
11805 if (totalPCMFrameCountOut) {
11806 *totalPCMFrameCountOut = 0;
11807 }
11808
11809 pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
11810 if (pFlac == NULL) {
11811 return NULL;
11812 }
11813
11814 return drflac__full_read_and_close_s16(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
11815}
11816
11817DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
11818{
11819 drflac* pFlac;
11820
11821 if (channelsOut) {
11822 *channelsOut = 0;
11823 }
11824 if (sampleRateOut) {
11825 *sampleRateOut = 0;
11826 }
11827 if (totalPCMFrameCountOut) {
11828 *totalPCMFrameCountOut = 0;
11829 }
11830
11831 pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
11832 if (pFlac == NULL) {
11833 return NULL;
11834 }
11835
11836 return drflac__full_read_and_close_f32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
11837}
11838
11839#ifndef DR_FLAC_NO_STDIO
11840DRFLAC_API drflac_int32* drflac_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
11841{
11842 drflac* pFlac;
11843
11844 if (sampleRate) {
11845 *sampleRate = 0;
11846 }
11847 if (channels) {
11848 *channels = 0;
11849 }
11850 if (totalPCMFrameCount) {
11851 *totalPCMFrameCount = 0;
11852 }
11853
11854 pFlac = drflac_open_file(filename, pAllocationCallbacks);
11855 if (pFlac == NULL) {
11856 return NULL;
11857 }
11858
11859 return drflac__full_read_and_close_s32(pFlac, channels, sampleRate, totalPCMFrameCount);
11860}
11861
11862DRFLAC_API drflac_int16* drflac_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
11863{
11864 drflac* pFlac;
11865
11866 if (sampleRate) {
11867 *sampleRate = 0;
11868 }
11869 if (channels) {
11870 *channels = 0;
11871 }
11872 if (totalPCMFrameCount) {
11873 *totalPCMFrameCount = 0;
11874 }
11875
11876 pFlac = drflac_open_file(filename, pAllocationCallbacks);
11877 if (pFlac == NULL) {
11878 return NULL;
11879 }
11880
11881 return drflac__full_read_and_close_s16(pFlac, channels, sampleRate, totalPCMFrameCount);
11882}
11883
11884DRFLAC_API float* drflac_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
11885{
11886 drflac* pFlac;
11887
11888 if (sampleRate) {
11889 *sampleRate = 0;
11890 }
11891 if (channels) {
11892 *channels = 0;
11893 }
11894 if (totalPCMFrameCount) {
11895 *totalPCMFrameCount = 0;
11896 }
11897
11898 pFlac = drflac_open_file(filename, pAllocationCallbacks);
11899 if (pFlac == NULL) {
11900 return NULL;
11901 }
11902
11903 return drflac__full_read_and_close_f32(pFlac, channels, sampleRate, totalPCMFrameCount);
11904}
11905#endif
11906
11907DRFLAC_API drflac_int32* drflac_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
11908{
11909 drflac* pFlac;
11910
11911 if (sampleRate) {
11912 *sampleRate = 0;
11913 }
11914 if (channels) {
11915 *channels = 0;
11916 }
11917 if (totalPCMFrameCount) {
11918 *totalPCMFrameCount = 0;
11919 }
11920
11921 pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks);
11922 if (pFlac == NULL) {
11923 return NULL;
11924 }
11925
11926 return drflac__full_read_and_close_s32(pFlac, channels, sampleRate, totalPCMFrameCount);
11927}
11928
11929DRFLAC_API drflac_int16* drflac_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
11930{
11931 drflac* pFlac;
11932
11933 if (sampleRate) {
11934 *sampleRate = 0;
11935 }
11936 if (channels) {
11937 *channels = 0;
11938 }
11939 if (totalPCMFrameCount) {
11940 *totalPCMFrameCount = 0;
11941 }
11942
11943 pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks);
11944 if (pFlac == NULL) {
11945 return NULL;
11946 }
11947
11948 return drflac__full_read_and_close_s16(pFlac, channels, sampleRate, totalPCMFrameCount);
11949}
11950
11951DRFLAC_API float* drflac_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
11952{
11953 drflac* pFlac;
11954
11955 if (sampleRate) {
11956 *sampleRate = 0;
11957 }
11958 if (channels) {
11959 *channels = 0;
11960 }
11961 if (totalPCMFrameCount) {
11962 *totalPCMFrameCount = 0;
11963 }
11964
11965 pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks);
11966 if (pFlac == NULL) {
11967 return NULL;
11968 }
11969
11970 return drflac__full_read_and_close_f32(pFlac, channels, sampleRate, totalPCMFrameCount);
11971}
11972
11973
11974DRFLAC_API void drflac_free(void* p, const drflac_allocation_callbacks* pAllocationCallbacks)
11975{
11976 if (pAllocationCallbacks != NULL) {
11977 drflac__free_from_callbacks(p, pAllocationCallbacks);
11978 } else {
11979 drflac__free_default(p, NULL);
11980 }
11981}
11982
11983
11984
11985
11986DRFLAC_API void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const void* pComments)
11987{
11988 if (pIter == NULL) {
11989 return;
11990 }
11991
11992 pIter->countRemaining = commentCount;
11993 pIter->pRunningData = (const char*)pComments;
11994}
11995
11996DRFLAC_API const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut)
11997{
11998 drflac_int32 length;
11999 const char* pComment;
12000
12001 /* Safety. */
12002 if (pCommentLengthOut) {
12003 *pCommentLengthOut = 0;
12004 }
12005
12006 if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) {
12007 return NULL;
12008 }
12009
12010 length = drflac__le2host_32_ptr_unaligned(pIter->pRunningData);
12011 pIter->pRunningData += 4;
12012
12013 pComment = pIter->pRunningData;
12014 pIter->pRunningData += length;
12015 pIter->countRemaining -= 1;
12016
12017 if (pCommentLengthOut) {
12018 *pCommentLengthOut = length;
12019 }
12020
12021 return pComment;
12022}
12023
12024
12025
12026
12027DRFLAC_API void drflac_init_cuesheet_track_iterator(drflac_cuesheet_track_iterator* pIter, drflac_uint32 trackCount, const void* pTrackData)
12028{
12029 if (pIter == NULL) {
12030 return;
12031 }
12032
12033 pIter->countRemaining = trackCount;
12034 pIter->pRunningData = (const char*)pTrackData;
12035}
12036
12037DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter, drflac_cuesheet_track* pCuesheetTrack)
12038{
12039 drflac_cuesheet_track cuesheetTrack;
12040 const char* pRunningData;
12041 drflac_uint64 offsetHi;
12042 drflac_uint64 offsetLo;
12043
12044 if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) {
12045 return DRFLAC_FALSE;
12046 }
12047
12048 pRunningData = pIter->pRunningData;
12049
12050 offsetHi = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
12051 offsetLo = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
12052 cuesheetTrack.offset = offsetLo | (offsetHi << 32);
12053 cuesheetTrack.trackNumber = pRunningData[0]; pRunningData += 1;
12054 DRFLAC_COPY_MEMORY(cuesheetTrack.ISRC, pRunningData, sizeof(cuesheetTrack.ISRC)); pRunningData += 12;
12055 cuesheetTrack.isAudio = (pRunningData[0] & 0x80) != 0;
12056 cuesheetTrack.preEmphasis = (pRunningData[0] & 0x40) != 0; pRunningData += 14;
12057 cuesheetTrack.indexCount = pRunningData[0]; pRunningData += 1;
12058 cuesheetTrack.pIndexPoints = (const drflac_cuesheet_track_index*)pRunningData; pRunningData += cuesheetTrack.indexCount * sizeof(drflac_cuesheet_track_index);
12059
12060 pIter->pRunningData = pRunningData;
12061 pIter->countRemaining -= 1;
12062
12063 if (pCuesheetTrack) {
12064 *pCuesheetTrack = cuesheetTrack;
12065 }
12066
12067 return DRFLAC_TRUE;
12068}
12069
12070#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
12071 #pragma GCC diagnostic pop
12072#endif
12073#endif /* dr_flac_c */
12074#endif /* DR_FLAC_IMPLEMENTATION */
12075
12076
12077/*
12078REVISION HISTORY
12079================
12080v0.12.42 - 2023-11-02
12081 - Fix build for ARMv6-M.
12082 - Fix a compilation warning with GCC.
12083
12084v0.12.41 - 2023-06-17
12085 - Fix an incorrect date in revision history. No functional change.
12086
12087v0.12.40 - 2023-05-22
12088 - Minor code restructure. No functional change.
12089
12090v0.12.39 - 2022-09-17
12091 - Fix compilation with DJGPP.
12092 - Fix compilation error with Visual Studio 2019 and the ARM build.
12093 - Fix an error with SSE 4.1 detection.
12094 - Add support for disabling wchar_t with DR_WAV_NO_WCHAR.
12095 - Improve compatibility with compilers which lack support for explicit struct packing.
12096 - Improve compatibility with low-end and embedded hardware by reducing the amount of stack
12097 allocation when loading an Ogg encapsulated file.
12098
12099v0.12.38 - 2022-04-10
12100 - Fix compilation error on older versions of GCC.
12101
12102v0.12.37 - 2022-02-12
12103 - Improve ARM detection.
12104
12105v0.12.36 - 2022-02-07
12106 - Fix a compilation error with the ARM build.
12107
12108v0.12.35 - 2022-02-06
12109 - Fix a bug due to underestimating the amount of precision required for the prediction stage.
12110 - Fix some bugs found from fuzz testing.
12111
12112v0.12.34 - 2022-01-07
12113 - Fix some misalignment bugs when reading metadata.
12114
12115v0.12.33 - 2021-12-22
12116 - Fix a bug with seeking when the seek table does not start at PCM frame 0.
12117
12118v0.12.32 - 2021-12-11
12119 - Fix a warning with Clang.
12120
12121v0.12.31 - 2021-08-16
12122 - Silence some warnings.
12123
12124v0.12.30 - 2021-07-31
12125 - Fix platform detection for ARM64.
12126
12127v0.12.29 - 2021-04-02
12128 - Fix a bug where the running PCM frame index is set to an invalid value when over-seeking.
12129 - Fix a decoding error due to an incorrect validation check.
12130
12131v0.12.28 - 2021-02-21
12132 - Fix a warning due to referencing _MSC_VER when it is undefined.
12133
12134v0.12.27 - 2021-01-31
12135 - Fix a static analysis warning.
12136
12137v0.12.26 - 2021-01-17
12138 - Fix a compilation warning due to _BSD_SOURCE being deprecated.
12139
12140v0.12.25 - 2020-12-26
12141 - Update documentation.
12142
12143v0.12.24 - 2020-11-29
12144 - Fix ARM64/NEON detection when compiling with MSVC.
12145
12146v0.12.23 - 2020-11-21
12147 - Fix compilation with OpenWatcom.
12148
12149v0.12.22 - 2020-11-01
12150 - Fix an error with the previous release.
12151
12152v0.12.21 - 2020-11-01
12153 - Fix a possible deadlock when seeking.
12154 - Improve compiler support for older versions of GCC.
12155
12156v0.12.20 - 2020-09-08
12157 - Fix a compilation error on older compilers.
12158
12159v0.12.19 - 2020-08-30
12160 - Fix a bug due to an undefined 32-bit shift.
12161
12162v0.12.18 - 2020-08-14
12163 - Fix a crash when compiling with clang-cl.
12164
12165v0.12.17 - 2020-08-02
12166 - Simplify sized types.
12167
12168v0.12.16 - 2020-07-25
12169 - Fix a compilation warning.
12170
12171v0.12.15 - 2020-07-06
12172 - Check for negative LPC shifts and return an error.
12173
12174v0.12.14 - 2020-06-23
12175 - Add include guard for the implementation section.
12176
12177v0.12.13 - 2020-05-16
12178 - Add compile-time and run-time version querying.
12179 - DRFLAC_VERSION_MINOR
12180 - DRFLAC_VERSION_MAJOR
12181 - DRFLAC_VERSION_REVISION
12182 - DRFLAC_VERSION_STRING
12183 - drflac_version()
12184 - drflac_version_string()
12185
12186v0.12.12 - 2020-04-30
12187 - Fix compilation errors with VC6.
12188
12189v0.12.11 - 2020-04-19
12190 - Fix some pedantic warnings.
12191 - Fix some undefined behaviour warnings.
12192
12193v0.12.10 - 2020-04-10
12194 - Fix some bugs when trying to seek with an invalid seek table.
12195
12196v0.12.9 - 2020-04-05
12197 - Fix warnings.
12198
12199v0.12.8 - 2020-04-04
12200 - Add drflac_open_file_w() and drflac_open_file_with_metadata_w().
12201 - Fix some static analysis warnings.
12202 - Minor documentation updates.
12203
12204v0.12.7 - 2020-03-14
12205 - Fix compilation errors with VC6.
12206
12207v0.12.6 - 2020-03-07
12208 - Fix compilation error with Visual Studio .NET 2003.
12209
12210v0.12.5 - 2020-01-30
12211 - Silence some static analysis warnings.
12212
12213v0.12.4 - 2020-01-29
12214 - Silence some static analysis warnings.
12215
12216v0.12.3 - 2019-12-02
12217 - Fix some warnings when compiling with GCC and the -Og flag.
12218 - Fix a crash in out-of-memory situations.
12219 - Fix potential integer overflow bug.
12220 - Fix some static analysis warnings.
12221 - Fix a possible crash when using custom memory allocators without a custom realloc() implementation.
12222 - Fix a bug with binary search seeking where the bits per sample is not a multiple of 8.
12223
12224v0.12.2 - 2019-10-07
12225 - Internal code clean up.
12226
12227v0.12.1 - 2019-09-29
12228 - Fix some Clang Static Analyzer warnings.
12229 - Fix an unused variable warning.
12230
12231v0.12.0 - 2019-09-23
12232 - API CHANGE: Add support for user defined memory allocation routines. This system allows the program to specify their own memory allocation
12233 routines with a user data pointer for client-specific contextual data. This adds an extra parameter to the end of the following APIs:
12234 - drflac_open()
12235 - drflac_open_relaxed()
12236 - drflac_open_with_metadata()
12237 - drflac_open_with_metadata_relaxed()
12238 - drflac_open_file()
12239 - drflac_open_file_with_metadata()
12240 - drflac_open_memory()
12241 - drflac_open_memory_with_metadata()
12242 - drflac_open_and_read_pcm_frames_s32()
12243 - drflac_open_and_read_pcm_frames_s16()
12244 - drflac_open_and_read_pcm_frames_f32()
12245 - drflac_open_file_and_read_pcm_frames_s32()
12246 - drflac_open_file_and_read_pcm_frames_s16()
12247 - drflac_open_file_and_read_pcm_frames_f32()
12248 - drflac_open_memory_and_read_pcm_frames_s32()
12249 - drflac_open_memory_and_read_pcm_frames_s16()
12250 - drflac_open_memory_and_read_pcm_frames_f32()
12251 Set this extra parameter to NULL to use defaults which is the same as the previous behaviour. Setting this NULL will use
12252 DRFLAC_MALLOC, DRFLAC_REALLOC and DRFLAC_FREE.
12253 - Remove deprecated APIs:
12254 - drflac_read_s32()
12255 - drflac_read_s16()
12256 - drflac_read_f32()
12257 - drflac_seek_to_sample()
12258 - drflac_open_and_decode_s32()
12259 - drflac_open_and_decode_s16()
12260 - drflac_open_and_decode_f32()
12261 - drflac_open_and_decode_file_s32()
12262 - drflac_open_and_decode_file_s16()
12263 - drflac_open_and_decode_file_f32()
12264 - drflac_open_and_decode_memory_s32()
12265 - drflac_open_and_decode_memory_s16()
12266 - drflac_open_and_decode_memory_f32()
12267 - Remove drflac.totalSampleCount which is now replaced with drflac.totalPCMFrameCount. You can emulate drflac.totalSampleCount
12268 by doing pFlac->totalPCMFrameCount*pFlac->channels.
12269 - Rename drflac.currentFrame to drflac.currentFLACFrame to remove ambiguity with PCM frames.
12270 - Fix errors when seeking to the end of a stream.
12271 - Optimizations to seeking.
12272 - SSE improvements and optimizations.
12273 - ARM NEON optimizations.
12274 - Optimizations to drflac_read_pcm_frames_s16().
12275 - Optimizations to drflac_read_pcm_frames_s32().
12276
12277v0.11.10 - 2019-06-26
12278 - Fix a compiler error.
12279
12280v0.11.9 - 2019-06-16
12281 - Silence some ThreadSanitizer warnings.
12282
12283v0.11.8 - 2019-05-21
12284 - Fix warnings.
12285
12286v0.11.7 - 2019-05-06
12287 - C89 fixes.
12288
12289v0.11.6 - 2019-05-05
12290 - Add support for C89.
12291 - Fix a compiler warning when CRC is disabled.
12292 - Change license to choice of public domain or MIT-0.
12293
12294v0.11.5 - 2019-04-19
12295 - Fix a compiler error with GCC.
12296
12297v0.11.4 - 2019-04-17
12298 - Fix some warnings with GCC when compiling with -std=c99.
12299
12300v0.11.3 - 2019-04-07
12301 - Silence warnings with GCC.
12302
12303v0.11.2 - 2019-03-10
12304 - Fix a warning.
12305
12306v0.11.1 - 2019-02-17
12307 - Fix a potential bug with seeking.
12308
12309v0.11.0 - 2018-12-16
12310 - API CHANGE: Deprecated drflac_read_s32(), drflac_read_s16() and drflac_read_f32() and replaced them with
12311 drflac_read_pcm_frames_s32(), drflac_read_pcm_frames_s16() and drflac_read_pcm_frames_f32(). The new APIs take
12312 and return PCM frame counts instead of sample counts. To upgrade you will need to change the input count by
12313 dividing it by the channel count, and then do the same with the return value.
12314 - API_CHANGE: Deprecated drflac_seek_to_sample() and replaced with drflac_seek_to_pcm_frame(). Same rules as
12315 the changes to drflac_read_*() apply.
12316 - API CHANGE: Deprecated drflac_open_and_decode_*() and replaced with drflac_open_*_and_read_*(). Same rules as
12317 the changes to drflac_read_*() apply.
12318 - Optimizations.
12319
12320v0.10.0 - 2018-09-11
12321 - Remove the DR_FLAC_NO_WIN32_IO option and the Win32 file IO functionality. If you need to use Win32 file IO you
12322 need to do it yourself via the callback API.
12323 - Fix the clang build.
12324 - Fix undefined behavior.
12325 - Fix errors with CUESHEET metdata blocks.
12326 - Add an API for iterating over each cuesheet track in the CUESHEET metadata block. This works the same way as the
12327 Vorbis comment API.
12328 - Other miscellaneous bug fixes, mostly relating to invalid FLAC streams.
12329 - Minor optimizations.
12330
12331v0.9.11 - 2018-08-29
12332 - Fix a bug with sample reconstruction.
12333
12334v0.9.10 - 2018-08-07
12335 - Improve 64-bit detection.
12336
12337v0.9.9 - 2018-08-05
12338 - Fix C++ build on older versions of GCC.
12339
12340v0.9.8 - 2018-07-24
12341 - Fix compilation errors.
12342
12343v0.9.7 - 2018-07-05
12344 - Fix a warning.
12345
12346v0.9.6 - 2018-06-29
12347 - Fix some typos.
12348
12349v0.9.5 - 2018-06-23
12350 - Fix some warnings.
12351
12352v0.9.4 - 2018-06-14
12353 - Optimizations to seeking.
12354 - Clean up.
12355
12356v0.9.3 - 2018-05-22
12357 - Bug fix.
12358
12359v0.9.2 - 2018-05-12
12360 - Fix a compilation error due to a missing break statement.
12361
12362v0.9.1 - 2018-04-29
12363 - Fix compilation error with Clang.
12364
12365v0.9 - 2018-04-24
12366 - Fix Clang build.
12367 - Start using major.minor.revision versioning.
12368
12369v0.8g - 2018-04-19
12370 - Fix build on non-x86/x64 architectures.
12371
12372v0.8f - 2018-02-02
12373 - Stop pretending to support changing rate/channels mid stream.
12374
12375v0.8e - 2018-02-01
12376 - Fix a crash when the block size of a frame is larger than the maximum block size defined by the FLAC stream.
12377 - Fix a crash the the Rice partition order is invalid.
12378
12379v0.8d - 2017-09-22
12380 - Add support for decoding streams with ID3 tags. ID3 tags are just skipped.
12381
12382v0.8c - 2017-09-07
12383 - Fix warning on non-x86/x64 architectures.
12384
12385v0.8b - 2017-08-19
12386 - Fix build on non-x86/x64 architectures.
12387
12388v0.8a - 2017-08-13
12389 - A small optimization for the Clang build.
12390
12391v0.8 - 2017-08-12
12392 - API CHANGE: Rename dr_* types to drflac_*.
12393 - Optimizations. This brings dr_flac back to about the same class of efficiency as the reference implementation.
12394 - Add support for custom implementations of malloc(), realloc(), etc.
12395 - Add CRC checking to Ogg encapsulated streams.
12396 - Fix VC++ 6 build. This is only for the C++ compiler. The C compiler is not currently supported.
12397 - Bug fixes.
12398
12399v0.7 - 2017-07-23
12400 - Add support for opening a stream without a header block. To do this, use drflac_open_relaxed() / drflac_open_with_metadata_relaxed().
12401
12402v0.6 - 2017-07-22
12403 - Add support for recovering from invalid frames. With this change, dr_flac will simply skip over invalid frames as if they
12404 never existed. Frames are checked against their sync code, the CRC-8 of the frame header and the CRC-16 of the whole frame.
12405
12406v0.5 - 2017-07-16
12407 - Fix typos.
12408 - Change drflac_bool* types to unsigned.
12409 - Add CRC checking. This makes dr_flac slower, but can be disabled with #define DR_FLAC_NO_CRC.
12410
12411v0.4f - 2017-03-10
12412 - Fix a couple of bugs with the bitstreaming code.
12413
12414v0.4e - 2017-02-17
12415 - Fix some warnings.
12416
12417v0.4d - 2016-12-26
12418 - Add support for 32-bit floating-point PCM decoding.
12419 - Use drflac_int* and drflac_uint* sized types to improve compiler support.
12420 - Minor improvements to documentation.
12421
12422v0.4c - 2016-12-26
12423 - Add support for signed 16-bit integer PCM decoding.
12424
12425v0.4b - 2016-10-23
12426 - A minor change to drflac_bool8 and drflac_bool32 types.
12427
12428v0.4a - 2016-10-11
12429 - Rename drBool32 to drflac_bool32 for styling consistency.
12430
12431v0.4 - 2016-09-29
12432 - API/ABI CHANGE: Use fixed size 32-bit booleans instead of the built-in bool type.
12433 - API CHANGE: Rename drflac_open_and_decode*() to drflac_open_and_decode*_s32().
12434 - API CHANGE: Swap the order of "channels" and "sampleRate" parameters in drflac_open_and_decode*(). Rationale for this is to
12435 keep it consistent with drflac_audio.
12436
12437v0.3f - 2016-09-21
12438 - Fix a warning with GCC.
12439
12440v0.3e - 2016-09-18
12441 - Fixed a bug where GCC 4.3+ was not getting properly identified.
12442 - Fixed a few typos.
12443 - Changed date formats to ISO 8601 (YYYY-MM-DD).
12444
12445v0.3d - 2016-06-11
12446 - Minor clean up.
12447
12448v0.3c - 2016-05-28
12449 - Fixed compilation error.
12450
12451v0.3b - 2016-05-16
12452 - Fixed Linux/GCC build.
12453 - Updated documentation.
12454
12455v0.3a - 2016-05-15
12456 - Minor fixes to documentation.
12457
12458v0.3 - 2016-05-11
12459 - Optimizations. Now at about parity with the reference implementation on 32-bit builds.
12460 - Lots of clean up.
12461
12462v0.2b - 2016-05-10
12463 - Bug fixes.
12464
12465v0.2a - 2016-05-10
12466 - Made drflac_open_and_decode() more robust.
12467 - Removed an unused debugging variable
12468
12469v0.2 - 2016-05-09
12470 - Added support for Ogg encapsulation.
12471 - API CHANGE. Have the onSeek callback take a third argument which specifies whether or not the seek
12472 should be relative to the start or the current position. Also changes the seeking rules such that
12473 seeking offsets will never be negative.
12474 - Have drflac_open_and_decode() fail gracefully if the stream has an unknown total sample count.
12475
12476v0.1b - 2016-05-07
12477 - Properly close the file handle in drflac_open_file() and family when the decoder fails to initialize.
12478 - Removed a stale comment.
12479
12480v0.1a - 2016-05-05
12481 - Minor formatting changes.
12482 - Fixed a warning on the GCC build.
12483
12484v0.1 - 2016-05-03
12485 - Initial versioned release.
12486*/
12487
12488/*
12489This software is available as a choice of the following licenses. Choose
12490whichever you prefer.
12491
12492===============================================================================
12493ALTERNATIVE 1 - Public Domain (www.unlicense.org)
12494===============================================================================
12495This is free and unencumbered software released into the public domain.
12496
12497Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
12498software, either in source code form or as a compiled binary, for any purpose,
12499commercial or non-commercial, and by any means.
12500
12501In jurisdictions that recognize copyright laws, the author or authors of this
12502software dedicate any and all copyright interest in the software to the public
12503domain. We make this dedication for the benefit of the public at large and to
12504the detriment of our heirs and successors. We intend this dedication to be an
12505overt act of relinquishment in perpetuity of all present and future rights to
12506this software under copyright law.
12507
12508THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12509IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12510FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
12511AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
12512ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
12513WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12514
12515For more information, please refer to <http://unlicense.org/>
12516
12517===============================================================================
12518ALTERNATIVE 2 - MIT No Attribution
12519===============================================================================
12520Copyright 2023 David Reid
12521
12522Permission is hereby granted, free of charge, to any person obtaining a copy of
12523this software and associated documentation files (the "Software"), to deal in
12524the Software without restriction, including without limitation the rights to
12525use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12526of the Software, and to permit persons to whom the Software is furnished to do
12527so.
12528
12529THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12530IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12531FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
12532AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
12533LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
12534OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
12535SOFTWARE.
12536*/
diff --git a/raylib/src/external/dr_mp3.h b/raylib/src/external/dr_mp3.h
new file mode 100644
index 0000000..e1a66d9
--- /dev/null
+++ b/raylib/src/external/dr_mp3.h
@@ -0,0 +1,4837 @@
1/*
2MP3 audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
3dr_mp3 - v0.6.39 - 2024-02-27
4
5David Reid - mackron@gmail.com
6
7GitHub: https://github.com/mackron/dr_libs
8
9Based on minimp3 (https://github.com/lieff/minimp3) which is where the real work was done. See the bottom of this file for differences between minimp3 and dr_mp3.
10*/
11
12/*
13RELEASE NOTES - VERSION 0.6
14===========================
15Version 0.6 includes breaking changes with the configuration of decoders. The ability to customize the number of output channels and the sample rate has been
16removed. You must now use the channel count and sample rate reported by the MP3 stream itself, and all channel and sample rate conversion must be done
17yourself.
18
19
20Changes to Initialization
21-------------------------
22Previously, `drmp3_init()`, etc. took a pointer to a `drmp3_config` object that allowed you to customize the output channels and sample rate. This has been
23removed. If you need the old behaviour you will need to convert the data yourself or just not upgrade. The following APIs have changed.
24
25 `drmp3_init()`
26 `drmp3_init_memory()`
27 `drmp3_init_file()`
28
29
30Miscellaneous Changes
31---------------------
32Support for loading a file from a `wchar_t` string has been added via the `drmp3_init_file_w()` API.
33*/
34
35/*
36Introducation
37=============
38dr_mp3 is a single file library. To use it, do something like the following in one .c file.
39
40 ```c
41 #define DR_MP3_IMPLEMENTATION
42 #include "dr_mp3.h"
43 ```
44
45You 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:
46
47 ```c
48 drmp3 mp3;
49 if (!drmp3_init_file(&mp3, "MySong.mp3", NULL)) {
50 // Failed to open file
51 }
52
53 ...
54
55 drmp3_uint64 framesRead = drmp3_read_pcm_frames_f32(pMP3, framesToRead, pFrames);
56 ```
57
58The drmp3 object is transparent so you can get access to the channel count and sample rate like so:
59
60 ```
61 drmp3_uint32 channels = mp3.channels;
62 drmp3_uint32 sampleRate = mp3.sampleRate;
63 ```
64
65The example above initializes a decoder from a file, but you can also initialize it from a block of memory and read and seek callbacks with
66`drmp3_init_memory()` and `drmp3_init()` respectively.
67
68You do not need to do any annoying memory management when reading PCM frames - this is all managed internally. You can request any number of PCM frames in each
69call to `drmp3_read_pcm_frames_f32()` and it will return as many PCM frames as it can, up to the requested amount.
70
71You can also decode an entire file in one go with `drmp3_open_and_read_pcm_frames_f32()`, `drmp3_open_memory_and_read_pcm_frames_f32()` and
72`drmp3_open_file_and_read_pcm_frames_f32()`.
73
74
75Build Options
76=============
77#define these options before including this file.
78
79#define DR_MP3_NO_STDIO
80 Disable drmp3_init_file(), etc.
81
82#define DR_MP3_NO_SIMD
83 Disable SIMD optimizations.
84*/
85
86#ifndef dr_mp3_h
87#define dr_mp3_h
88
89#ifdef __cplusplus
90extern "C" {
91#endif
92
93#define DRMP3_STRINGIFY(x) #x
94#define DRMP3_XSTRINGIFY(x) DRMP3_STRINGIFY(x)
95
96#define DRMP3_VERSION_MAJOR 0
97#define DRMP3_VERSION_MINOR 6
98#define DRMP3_VERSION_REVISION 39
99#define DRMP3_VERSION_STRING DRMP3_XSTRINGIFY(DRMP3_VERSION_MAJOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_MINOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_REVISION)
100
101#include <stddef.h> /* For size_t. */
102
103/* Sized Types */
104typedef signed char drmp3_int8;
105typedef unsigned char drmp3_uint8;
106typedef signed short drmp3_int16;
107typedef unsigned short drmp3_uint16;
108typedef signed int drmp3_int32;
109typedef unsigned int drmp3_uint32;
110#if defined(_MSC_VER) && !defined(__clang__)
111 typedef signed __int64 drmp3_int64;
112 typedef unsigned __int64 drmp3_uint64;
113#else
114 #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
115 #pragma GCC diagnostic push
116 #pragma GCC diagnostic ignored "-Wlong-long"
117 #if defined(__clang__)
118 #pragma GCC diagnostic ignored "-Wc++11-long-long"
119 #endif
120 #endif
121 typedef signed long long drmp3_int64;
122 typedef unsigned long long drmp3_uint64;
123 #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
124 #pragma GCC diagnostic pop
125 #endif
126#endif
127#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__)
128 typedef drmp3_uint64 drmp3_uintptr;
129#else
130 typedef drmp3_uint32 drmp3_uintptr;
131#endif
132typedef drmp3_uint8 drmp3_bool8;
133typedef drmp3_uint32 drmp3_bool32;
134#define DRMP3_TRUE 1
135#define DRMP3_FALSE 0
136/* End Sized Types */
137
138/* Decorations */
139#if !defined(DRMP3_API)
140 #if defined(DRMP3_DLL)
141 #if defined(_WIN32)
142 #define DRMP3_DLL_IMPORT __declspec(dllimport)
143 #define DRMP3_DLL_EXPORT __declspec(dllexport)
144 #define DRMP3_DLL_PRIVATE static
145 #else
146 #if defined(__GNUC__) && __GNUC__ >= 4
147 #define DRMP3_DLL_IMPORT __attribute__((visibility("default")))
148 #define DRMP3_DLL_EXPORT __attribute__((visibility("default")))
149 #define DRMP3_DLL_PRIVATE __attribute__((visibility("hidden")))
150 #else
151 #define DRMP3_DLL_IMPORT
152 #define DRMP3_DLL_EXPORT
153 #define DRMP3_DLL_PRIVATE static
154 #endif
155 #endif
156
157 #if defined(DR_MP3_IMPLEMENTATION) || defined(DRMP3_IMPLEMENTATION)
158 #define DRMP3_API DRMP3_DLL_EXPORT
159 #else
160 #define DRMP3_API DRMP3_DLL_IMPORT
161 #endif
162 #define DRMP3_PRIVATE DRMP3_DLL_PRIVATE
163 #else
164 #define DRMP3_API extern
165 #define DRMP3_PRIVATE static
166 #endif
167#endif
168/* End Decorations */
169
170/* Result Codes */
171typedef drmp3_int32 drmp3_result;
172#define DRMP3_SUCCESS 0
173#define DRMP3_ERROR -1 /* A generic error. */
174#define DRMP3_INVALID_ARGS -2
175#define DRMP3_INVALID_OPERATION -3
176#define DRMP3_OUT_OF_MEMORY -4
177#define DRMP3_OUT_OF_RANGE -5
178#define DRMP3_ACCESS_DENIED -6
179#define DRMP3_DOES_NOT_EXIST -7
180#define DRMP3_ALREADY_EXISTS -8
181#define DRMP3_TOO_MANY_OPEN_FILES -9
182#define DRMP3_INVALID_FILE -10
183#define DRMP3_TOO_BIG -11
184#define DRMP3_PATH_TOO_LONG -12
185#define DRMP3_NAME_TOO_LONG -13
186#define DRMP3_NOT_DIRECTORY -14
187#define DRMP3_IS_DIRECTORY -15
188#define DRMP3_DIRECTORY_NOT_EMPTY -16
189#define DRMP3_END_OF_FILE -17
190#define DRMP3_NO_SPACE -18
191#define DRMP3_BUSY -19
192#define DRMP3_IO_ERROR -20
193#define DRMP3_INTERRUPT -21
194#define DRMP3_UNAVAILABLE -22
195#define DRMP3_ALREADY_IN_USE -23
196#define DRMP3_BAD_ADDRESS -24
197#define DRMP3_BAD_SEEK -25
198#define DRMP3_BAD_PIPE -26
199#define DRMP3_DEADLOCK -27
200#define DRMP3_TOO_MANY_LINKS -28
201#define DRMP3_NOT_IMPLEMENTED -29
202#define DRMP3_NO_MESSAGE -30
203#define DRMP3_BAD_MESSAGE -31
204#define DRMP3_NO_DATA_AVAILABLE -32
205#define DRMP3_INVALID_DATA -33
206#define DRMP3_TIMEOUT -34
207#define DRMP3_NO_NETWORK -35
208#define DRMP3_NOT_UNIQUE -36
209#define DRMP3_NOT_SOCKET -37
210#define DRMP3_NO_ADDRESS -38
211#define DRMP3_BAD_PROTOCOL -39
212#define DRMP3_PROTOCOL_UNAVAILABLE -40
213#define DRMP3_PROTOCOL_NOT_SUPPORTED -41
214#define DRMP3_PROTOCOL_FAMILY_NOT_SUPPORTED -42
215#define DRMP3_ADDRESS_FAMILY_NOT_SUPPORTED -43
216#define DRMP3_SOCKET_NOT_SUPPORTED -44
217#define DRMP3_CONNECTION_RESET -45
218#define DRMP3_ALREADY_CONNECTED -46
219#define DRMP3_NOT_CONNECTED -47
220#define DRMP3_CONNECTION_REFUSED -48
221#define DRMP3_NO_HOST -49
222#define DRMP3_IN_PROGRESS -50
223#define DRMP3_CANCELLED -51
224#define DRMP3_MEMORY_ALREADY_MAPPED -52
225#define DRMP3_AT_END -53
226/* End Result Codes */
227
228#define DRMP3_MAX_PCM_FRAMES_PER_MP3_FRAME 1152
229#define DRMP3_MAX_SAMPLES_PER_FRAME (DRMP3_MAX_PCM_FRAMES_PER_MP3_FRAME*2)
230
231/* Inline */
232#ifdef _MSC_VER
233 #define DRMP3_INLINE __forceinline
234#elif defined(__GNUC__)
235 /*
236 I've had a bug report where GCC is emitting warnings about functions possibly not being inlineable. This warning happens when
237 the __attribute__((always_inline)) attribute is defined without an "inline" statement. I think therefore there must be some
238 case where "__inline__" is not always defined, thus the compiler emitting these warnings. When using -std=c89 or -ansi on the
239 command line, we cannot use the "inline" keyword and instead need to use "__inline__". In an attempt to work around this issue
240 I am using "__inline__" only when we're compiling in strict ANSI mode.
241 */
242 #if defined(__STRICT_ANSI__)
243 #define DRMP3_GNUC_INLINE_HINT __inline__
244 #else
245 #define DRMP3_GNUC_INLINE_HINT inline
246 #endif
247
248 #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)) || defined(__clang__)
249 #define DRMP3_INLINE DRMP3_GNUC_INLINE_HINT __attribute__((always_inline))
250 #else
251 #define DRMP3_INLINE DRMP3_GNUC_INLINE_HINT
252 #endif
253#elif defined(__WATCOMC__)
254 #define DRMP3_INLINE __inline
255#else
256 #define DRMP3_INLINE
257#endif
258/* End Inline */
259
260
261DRMP3_API void drmp3_version(drmp3_uint32* pMajor, drmp3_uint32* pMinor, drmp3_uint32* pRevision);
262DRMP3_API const char* drmp3_version_string(void);
263
264
265/* Allocation Callbacks */
266typedef struct
267{
268 void* pUserData;
269 void* (* onMalloc)(size_t sz, void* pUserData);
270 void* (* onRealloc)(void* p, size_t sz, void* pUserData);
271 void (* onFree)(void* p, void* pUserData);
272} drmp3_allocation_callbacks;
273/* End Allocation Callbacks */
274
275
276/*
277Low Level Push API
278==================
279*/
280typedef struct
281{
282 int frame_bytes, channels, hz, layer, bitrate_kbps;
283} drmp3dec_frame_info;
284
285typedef struct
286{
287 float mdct_overlap[2][9*32], qmf_state[15*2*32];
288 int reserv, free_format_bytes;
289 drmp3_uint8 header[4], reserv_buf[511];
290} drmp3dec;
291
292/* Initializes a low level decoder. */
293DRMP3_API void drmp3dec_init(drmp3dec *dec);
294
295/* Reads a frame from a low level decoder. */
296DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int mp3_bytes, void *pcm, drmp3dec_frame_info *info);
297
298/* Helper for converting between f32 and s16. */
299DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num_samples);
300
301
302
303/*
304Main API (Pull API)
305===================
306*/
307typedef enum
308{
309 drmp3_seek_origin_start,
310 drmp3_seek_origin_current
311} drmp3_seek_origin;
312
313typedef struct
314{
315 drmp3_uint64 seekPosInBytes; /* Points to the first byte of an MP3 frame. */
316 drmp3_uint64 pcmFrameIndex; /* The index of the PCM frame this seek point targets. */
317 drmp3_uint16 mp3FramesToDiscard; /* The number of whole MP3 frames to be discarded before pcmFramesToDiscard. */
318 drmp3_uint16 pcmFramesToDiscard; /* The number of leading samples to read and discard. These are discarded after mp3FramesToDiscard. */
319} drmp3_seek_point;
320
321/*
322Callback for when data is read. Return value is the number of bytes actually read.
323
324pUserData [in] The user data that was passed to drmp3_init(), drmp3_open() and family.
325pBufferOut [out] The output buffer.
326bytesToRead [in] The number of bytes to read.
327
328Returns the number of bytes actually read.
329
330A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback until
331either the entire bytesToRead is filled or you have reached the end of the stream.
332*/
333typedef size_t (* drmp3_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead);
334
335/*
336Callback for when data needs to be seeked.
337
338pUserData [in] The user data that was passed to drmp3_init(), drmp3_open() and family.
339offset [in] The number of bytes to move, relative to the origin. Will never be negative.
340origin [in] The origin of the seek - the current position or the start of the stream.
341
342Returns whether or not the seek was successful.
343
344Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which
345will be either drmp3_seek_origin_start or drmp3_seek_origin_current.
346*/
347typedef drmp3_bool32 (* drmp3_seek_proc)(void* pUserData, int offset, drmp3_seek_origin origin);
348
349typedef struct
350{
351 drmp3_uint32 channels;
352 drmp3_uint32 sampleRate;
353} drmp3_config;
354
355typedef struct
356{
357 drmp3dec decoder;
358 drmp3_uint32 channels;
359 drmp3_uint32 sampleRate;
360 drmp3_read_proc onRead;
361 drmp3_seek_proc onSeek;
362 void* pUserData;
363 drmp3_allocation_callbacks allocationCallbacks;
364 drmp3_uint32 mp3FrameChannels; /* The number of channels in the currently loaded MP3 frame. Internal use only. */
365 drmp3_uint32 mp3FrameSampleRate; /* The sample rate of the currently loaded MP3 frame. Internal use only. */
366 drmp3_uint32 pcmFramesConsumedInMP3Frame;
367 drmp3_uint32 pcmFramesRemainingInMP3Frame;
368 drmp3_uint8 pcmFrames[sizeof(float)*DRMP3_MAX_SAMPLES_PER_FRAME]; /* <-- Multipled by sizeof(float) to ensure there's enough room for DR_MP3_FLOAT_OUTPUT. */
369 drmp3_uint64 currentPCMFrame; /* The current PCM frame, globally, based on the output sample rate. Mainly used for seeking. */
370 drmp3_uint64 streamCursor; /* The current byte the decoder is sitting on in the raw stream. */
371 drmp3_seek_point* pSeekPoints; /* NULL by default. Set with drmp3_bind_seek_table(). Memory is owned by the client. dr_mp3 will never attempt to free this pointer. */
372 drmp3_uint32 seekPointCount; /* The number of items in pSeekPoints. When set to 0 assumes to no seek table. Defaults to zero. */
373 size_t dataSize;
374 size_t dataCapacity;
375 size_t dataConsumed;
376 drmp3_uint8* pData;
377 drmp3_bool32 atEnd : 1;
378 struct
379 {
380 const drmp3_uint8* pData;
381 size_t dataSize;
382 size_t currentReadPos;
383 } memory; /* Only used for decoders that were opened against a block of memory. */
384} drmp3;
385
386/*
387Initializes an MP3 decoder.
388
389onRead [in] The function to call when data needs to be read from the client.
390onSeek [in] The function to call when the read position of the client data needs to move.
391pUserData [in, optional] A pointer to application defined data that will be passed to onRead and onSeek.
392
393Returns true if successful; false otherwise.
394
395Close the loader with drmp3_uninit().
396
397See also: drmp3_init_file(), drmp3_init_memory(), drmp3_uninit()
398*/
399DRMP3_API drmp3_bool32 drmp3_init(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, const drmp3_allocation_callbacks* pAllocationCallbacks);
400
401/*
402Initializes an MP3 decoder from a block of memory.
403
404This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for
405the lifetime of the drmp3 object.
406
407The buffer should contain the contents of the entire MP3 file.
408*/
409DRMP3_API drmp3_bool32 drmp3_init_memory(drmp3* pMP3, const void* pData, size_t dataSize, const drmp3_allocation_callbacks* pAllocationCallbacks);
410
411#ifndef DR_MP3_NO_STDIO
412/*
413Initializes an MP3 decoder from a file.
414
415This holds the internal FILE object until drmp3_uninit() is called. Keep this in mind if you're caching drmp3
416objects because the operating system may restrict the number of file handles an application can have open at
417any given time.
418*/
419DRMP3_API drmp3_bool32 drmp3_init_file(drmp3* pMP3, const char* pFilePath, const drmp3_allocation_callbacks* pAllocationCallbacks);
420DRMP3_API drmp3_bool32 drmp3_init_file_w(drmp3* pMP3, const wchar_t* pFilePath, const drmp3_allocation_callbacks* pAllocationCallbacks);
421#endif
422
423/*
424Uninitializes an MP3 decoder.
425*/
426DRMP3_API void drmp3_uninit(drmp3* pMP3);
427
428/*
429Reads PCM frames as interleaved 32-bit IEEE floating point PCM.
430
431Note that framesToRead specifies the number of PCM frames to read, _not_ the number of MP3 frames.
432*/
433DRMP3_API drmp3_uint64 drmp3_read_pcm_frames_f32(drmp3* pMP3, drmp3_uint64 framesToRead, float* pBufferOut);
434
435/*
436Reads PCM frames as interleaved signed 16-bit integer PCM.
437
438Note that framesToRead specifies the number of PCM frames to read, _not_ the number of MP3 frames.
439*/
440DRMP3_API drmp3_uint64 drmp3_read_pcm_frames_s16(drmp3* pMP3, drmp3_uint64 framesToRead, drmp3_int16* pBufferOut);
441
442/*
443Seeks to a specific frame.
444
445Note that this is _not_ an MP3 frame, but rather a PCM frame.
446*/
447DRMP3_API drmp3_bool32 drmp3_seek_to_pcm_frame(drmp3* pMP3, drmp3_uint64 frameIndex);
448
449/*
450Calculates the total number of PCM frames in the MP3 stream. Cannot be used for infinite streams such as internet
451radio. Runs in linear time. Returns 0 on error.
452*/
453DRMP3_API drmp3_uint64 drmp3_get_pcm_frame_count(drmp3* pMP3);
454
455/*
456Calculates the total number of MP3 frames in the MP3 stream. Cannot be used for infinite streams such as internet
457radio. Runs in linear time. Returns 0 on error.
458*/
459DRMP3_API drmp3_uint64 drmp3_get_mp3_frame_count(drmp3* pMP3);
460
461/*
462Calculates the total number of MP3 and PCM frames in the MP3 stream. Cannot be used for infinite streams such as internet
463radio. Runs in linear time. Returns 0 on error.
464
465This is equivalent to calling drmp3_get_mp3_frame_count() and drmp3_get_pcm_frame_count() except that it's more efficient.
466*/
467DRMP3_API drmp3_bool32 drmp3_get_mp3_and_pcm_frame_count(drmp3* pMP3, drmp3_uint64* pMP3FrameCount, drmp3_uint64* pPCMFrameCount);
468
469/*
470Calculates the seekpoints based on PCM frames. This is slow.
471
472pSeekpoint count is a pointer to a uint32 containing the seekpoint count. On input it contains the desired count.
473On output it contains the actual count. The reason for this design is that the client may request too many
474seekpoints, in which case dr_mp3 will return a corrected count.
475
476Note that seektable seeking is not quite sample exact when the MP3 stream contains inconsistent sample rates.
477*/
478DRMP3_API drmp3_bool32 drmp3_calculate_seek_points(drmp3* pMP3, drmp3_uint32* pSeekPointCount, drmp3_seek_point* pSeekPoints);
479
480/*
481Binds a seek table to the decoder.
482
483This does _not_ make a copy of pSeekPoints - it only references it. It is up to the application to ensure this
484remains valid while it is bound to the decoder.
485
486Use drmp3_calculate_seek_points() to calculate the seek points.
487*/
488DRMP3_API drmp3_bool32 drmp3_bind_seek_table(drmp3* pMP3, drmp3_uint32 seekPointCount, drmp3_seek_point* pSeekPoints);
489
490
491/*
492Opens an decodes an entire MP3 stream as a single operation.
493
494On output pConfig will receive the channel count and sample rate of the stream.
495
496Free the returned pointer with drmp3_free().
497*/
498DRMP3_API float* drmp3_open_and_read_pcm_frames_f32(drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks);
499DRMP3_API drmp3_int16* drmp3_open_and_read_pcm_frames_s16(drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks);
500
501DRMP3_API float* drmp3_open_memory_and_read_pcm_frames_f32(const void* pData, size_t dataSize, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks);
502DRMP3_API drmp3_int16* drmp3_open_memory_and_read_pcm_frames_s16(const void* pData, size_t dataSize, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks);
503
504#ifndef DR_MP3_NO_STDIO
505DRMP3_API float* drmp3_open_file_and_read_pcm_frames_f32(const char* filePath, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks);
506DRMP3_API drmp3_int16* drmp3_open_file_and_read_pcm_frames_s16(const char* filePath, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks);
507#endif
508
509/*
510Allocates a block of memory on the heap.
511*/
512DRMP3_API void* drmp3_malloc(size_t sz, const drmp3_allocation_callbacks* pAllocationCallbacks);
513
514/*
515Frees any memory that was allocated by a public drmp3 API.
516*/
517DRMP3_API void drmp3_free(void* p, const drmp3_allocation_callbacks* pAllocationCallbacks);
518
519#ifdef __cplusplus
520}
521#endif
522#endif /* dr_mp3_h */
523
524
525/************************************************************************************************************************************************************
526 ************************************************************************************************************************************************************
527
528 IMPLEMENTATION
529
530 ************************************************************************************************************************************************************
531 ************************************************************************************************************************************************************/
532#if defined(DR_MP3_IMPLEMENTATION) || defined(DRMP3_IMPLEMENTATION)
533#ifndef dr_mp3_c
534#define dr_mp3_c
535
536#include <stdlib.h>
537#include <string.h>
538#include <limits.h> /* For INT_MAX */
539
540DRMP3_API void drmp3_version(drmp3_uint32* pMajor, drmp3_uint32* pMinor, drmp3_uint32* pRevision)
541{
542 if (pMajor) {
543 *pMajor = DRMP3_VERSION_MAJOR;
544 }
545
546 if (pMinor) {
547 *pMinor = DRMP3_VERSION_MINOR;
548 }
549
550 if (pRevision) {
551 *pRevision = DRMP3_VERSION_REVISION;
552 }
553}
554
555DRMP3_API const char* drmp3_version_string(void)
556{
557 return DRMP3_VERSION_STRING;
558}
559
560/* Disable SIMD when compiling with TCC for now. */
561#if defined(__TINYC__)
562#define DR_MP3_NO_SIMD
563#endif
564
565#define DRMP3_OFFSET_PTR(p, offset) ((void*)((drmp3_uint8*)(p) + (offset)))
566
567#define DRMP3_MAX_FREE_FORMAT_FRAME_SIZE 2304 /* more than ISO spec's */
568#ifndef DRMP3_MAX_FRAME_SYNC_MATCHES
569#define DRMP3_MAX_FRAME_SYNC_MATCHES 10
570#endif
571
572#define DRMP3_MAX_L3_FRAME_PAYLOAD_BYTES DRMP3_MAX_FREE_FORMAT_FRAME_SIZE /* MUST be >= 320000/8/32000*1152 = 1440 */
573
574#define DRMP3_MAX_BITRESERVOIR_BYTES 511
575#define DRMP3_SHORT_BLOCK_TYPE 2
576#define DRMP3_STOP_BLOCK_TYPE 3
577#define DRMP3_MODE_MONO 3
578#define DRMP3_MODE_JOINT_STEREO 1
579#define DRMP3_HDR_SIZE 4
580#define DRMP3_HDR_IS_MONO(h) (((h[3]) & 0xC0) == 0xC0)
581#define DRMP3_HDR_IS_MS_STEREO(h) (((h[3]) & 0xE0) == 0x60)
582#define DRMP3_HDR_IS_FREE_FORMAT(h) (((h[2]) & 0xF0) == 0)
583#define DRMP3_HDR_IS_CRC(h) (!((h[1]) & 1))
584#define DRMP3_HDR_TEST_PADDING(h) ((h[2]) & 0x2)
585#define DRMP3_HDR_TEST_MPEG1(h) ((h[1]) & 0x8)
586#define DRMP3_HDR_TEST_NOT_MPEG25(h) ((h[1]) & 0x10)
587#define DRMP3_HDR_TEST_I_STEREO(h) ((h[3]) & 0x10)
588#define DRMP3_HDR_TEST_MS_STEREO(h) ((h[3]) & 0x20)
589#define DRMP3_HDR_GET_STEREO_MODE(h) (((h[3]) >> 6) & 3)
590#define DRMP3_HDR_GET_STEREO_MODE_EXT(h) (((h[3]) >> 4) & 3)
591#define DRMP3_HDR_GET_LAYER(h) (((h[1]) >> 1) & 3)
592#define DRMP3_HDR_GET_BITRATE(h) ((h[2]) >> 4)
593#define DRMP3_HDR_GET_SAMPLE_RATE(h) (((h[2]) >> 2) & 3)
594#define DRMP3_HDR_GET_MY_SAMPLE_RATE(h) (DRMP3_HDR_GET_SAMPLE_RATE(h) + (((h[1] >> 3) & 1) + ((h[1] >> 4) & 1))*3)
595#define DRMP3_HDR_IS_FRAME_576(h) ((h[1] & 14) == 2)
596#define DRMP3_HDR_IS_LAYER_1(h) ((h[1] & 6) == 6)
597
598#define DRMP3_BITS_DEQUANTIZER_OUT -1
599#define DRMP3_MAX_SCF (255 + DRMP3_BITS_DEQUANTIZER_OUT*4 - 210)
600#define DRMP3_MAX_SCFI ((DRMP3_MAX_SCF + 3) & ~3)
601
602#define DRMP3_MIN(a, b) ((a) > (b) ? (b) : (a))
603#define DRMP3_MAX(a, b) ((a) < (b) ? (b) : (a))
604
605#if !defined(DR_MP3_NO_SIMD)
606
607#if !defined(DR_MP3_ONLY_SIMD) && (defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__) || defined(_M_ARM64))
608/* x64 always have SSE2, arm64 always have neon, no need for generic code */
609#define DR_MP3_ONLY_SIMD
610#endif
611
612#if ((defined(_MSC_VER) && _MSC_VER >= 1400) && defined(_M_X64)) || ((defined(__i386) || defined(_M_IX86) || defined(__i386__) || defined(__x86_64__)) && ((defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__)))
613#if defined(_MSC_VER)
614#include <intrin.h>
615#endif
616#include <emmintrin.h>
617#define DRMP3_HAVE_SSE 1
618#define DRMP3_HAVE_SIMD 1
619#define DRMP3_VSTORE _mm_storeu_ps
620#define DRMP3_VLD _mm_loadu_ps
621#define DRMP3_VSET _mm_set1_ps
622#define DRMP3_VADD _mm_add_ps
623#define DRMP3_VSUB _mm_sub_ps
624#define DRMP3_VMUL _mm_mul_ps
625#define DRMP3_VMAC(a, x, y) _mm_add_ps(a, _mm_mul_ps(x, y))
626#define DRMP3_VMSB(a, x, y) _mm_sub_ps(a, _mm_mul_ps(x, y))
627#define DRMP3_VMUL_S(x, s) _mm_mul_ps(x, _mm_set1_ps(s))
628#define DRMP3_VREV(x) _mm_shuffle_ps(x, x, _MM_SHUFFLE(0, 1, 2, 3))
629typedef __m128 drmp3_f4;
630#if defined(_MSC_VER) || defined(DR_MP3_ONLY_SIMD)
631#define drmp3_cpuid __cpuid
632#else
633static __inline__ __attribute__((always_inline)) void drmp3_cpuid(int CPUInfo[], const int InfoType)
634{
635#if defined(__PIC__)
636 __asm__ __volatile__(
637#if defined(__x86_64__)
638 "push %%rbx\n"
639 "cpuid\n"
640 "xchgl %%ebx, %1\n"
641 "pop %%rbx\n"
642#else
643 "xchgl %%ebx, %1\n"
644 "cpuid\n"
645 "xchgl %%ebx, %1\n"
646#endif
647 : "=a" (CPUInfo[0]), "=r" (CPUInfo[1]), "=c" (CPUInfo[2]), "=d" (CPUInfo[3])
648 : "a" (InfoType));
649#else
650 __asm__ __volatile__(
651 "cpuid"
652 : "=a" (CPUInfo[0]), "=b" (CPUInfo[1]), "=c" (CPUInfo[2]), "=d" (CPUInfo[3])
653 : "a" (InfoType));
654#endif
655}
656#endif
657static int drmp3_have_simd(void)
658{
659#ifdef DR_MP3_ONLY_SIMD
660 return 1;
661#else
662 static int g_have_simd;
663 int CPUInfo[4];
664#ifdef MINIMP3_TEST
665 static int g_counter;
666 if (g_counter++ > 100)
667 return 0;
668#endif
669 if (g_have_simd)
670 goto end;
671 drmp3_cpuid(CPUInfo, 0);
672 if (CPUInfo[0] > 0)
673 {
674 drmp3_cpuid(CPUInfo, 1);
675 g_have_simd = (CPUInfo[3] & (1 << 26)) + 1; /* SSE2 */
676 return g_have_simd - 1;
677 }
678
679end:
680 return g_have_simd - 1;
681#endif
682}
683#elif defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64)
684#include <arm_neon.h>
685#define DRMP3_HAVE_SSE 0
686#define DRMP3_HAVE_SIMD 1
687#define DRMP3_VSTORE vst1q_f32
688#define DRMP3_VLD vld1q_f32
689#define DRMP3_VSET vmovq_n_f32
690#define DRMP3_VADD vaddq_f32
691#define DRMP3_VSUB vsubq_f32
692#define DRMP3_VMUL vmulq_f32
693#define DRMP3_VMAC(a, x, y) vmlaq_f32(a, x, y)
694#define DRMP3_VMSB(a, x, y) vmlsq_f32(a, x, y)
695#define DRMP3_VMUL_S(x, s) vmulq_f32(x, vmovq_n_f32(s))
696#define DRMP3_VREV(x) vcombine_f32(vget_high_f32(vrev64q_f32(x)), vget_low_f32(vrev64q_f32(x)))
697typedef float32x4_t drmp3_f4;
698static int drmp3_have_simd(void)
699{ /* TODO: detect neon for !DR_MP3_ONLY_SIMD */
700 return 1;
701}
702#else
703#define DRMP3_HAVE_SSE 0
704#define DRMP3_HAVE_SIMD 0
705#ifdef DR_MP3_ONLY_SIMD
706#error DR_MP3_ONLY_SIMD used, but SSE/NEON not enabled
707#endif
708#endif
709
710#else
711
712#define DRMP3_HAVE_SIMD 0
713
714#endif
715
716#if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64) && !defined(__ARM_ARCH_6M__)
717#define DRMP3_HAVE_ARMV6 1
718static __inline__ __attribute__((always_inline)) drmp3_int32 drmp3_clip_int16_arm(drmp3_int32 a)
719{
720 drmp3_int32 x = 0;
721 __asm__ ("ssat %0, #16, %1" : "=r"(x) : "r"(a));
722 return x;
723}
724#else
725#define DRMP3_HAVE_ARMV6 0
726#endif
727
728
729/* Standard library stuff. */
730#ifndef DRMP3_ASSERT
731#include <assert.h>
732#define DRMP3_ASSERT(expression) assert(expression)
733#endif
734#ifndef DRMP3_COPY_MEMORY
735#define DRMP3_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz))
736#endif
737#ifndef DRMP3_MOVE_MEMORY
738#define DRMP3_MOVE_MEMORY(dst, src, sz) memmove((dst), (src), (sz))
739#endif
740#ifndef DRMP3_ZERO_MEMORY
741#define DRMP3_ZERO_MEMORY(p, sz) memset((p), 0, (sz))
742#endif
743#define DRMP3_ZERO_OBJECT(p) DRMP3_ZERO_MEMORY((p), sizeof(*(p)))
744#ifndef DRMP3_MALLOC
745#define DRMP3_MALLOC(sz) malloc((sz))
746#endif
747#ifndef DRMP3_REALLOC
748#define DRMP3_REALLOC(p, sz) realloc((p), (sz))
749#endif
750#ifndef DRMP3_FREE
751#define DRMP3_FREE(p) free((p))
752#endif
753
754typedef struct
755{
756 const drmp3_uint8 *buf;
757 int pos, limit;
758} drmp3_bs;
759
760typedef struct
761{
762 float scf[3*64];
763 drmp3_uint8 total_bands, stereo_bands, bitalloc[64], scfcod[64];
764} drmp3_L12_scale_info;
765
766typedef struct
767{
768 drmp3_uint8 tab_offset, code_tab_width, band_count;
769} drmp3_L12_subband_alloc;
770
771typedef struct
772{
773 const drmp3_uint8 *sfbtab;
774 drmp3_uint16 part_23_length, big_values, scalefac_compress;
775 drmp3_uint8 global_gain, block_type, mixed_block_flag, n_long_sfb, n_short_sfb;
776 drmp3_uint8 table_select[3], region_count[3], subblock_gain[3];
777 drmp3_uint8 preflag, scalefac_scale, count1_table, scfsi;
778} drmp3_L3_gr_info;
779
780typedef struct
781{
782 drmp3_bs bs;
783 drmp3_uint8 maindata[DRMP3_MAX_BITRESERVOIR_BYTES + DRMP3_MAX_L3_FRAME_PAYLOAD_BYTES];
784 drmp3_L3_gr_info gr_info[4];
785 float grbuf[2][576], scf[40], syn[18 + 15][2*32];
786 drmp3_uint8 ist_pos[2][39];
787} drmp3dec_scratch;
788
789static void drmp3_bs_init(drmp3_bs *bs, const drmp3_uint8 *data, int bytes)
790{
791 bs->buf = data;
792 bs->pos = 0;
793 bs->limit = bytes*8;
794}
795
796static drmp3_uint32 drmp3_bs_get_bits(drmp3_bs *bs, int n)
797{
798 drmp3_uint32 next, cache = 0, s = bs->pos & 7;
799 int shl = n + s;
800 const drmp3_uint8 *p = bs->buf + (bs->pos >> 3);
801 if ((bs->pos += n) > bs->limit)
802 return 0;
803 next = *p++ & (255 >> s);
804 while ((shl -= 8) > 0)
805 {
806 cache |= next << shl;
807 next = *p++;
808 }
809 return cache | (next >> -shl);
810}
811
812static int drmp3_hdr_valid(const drmp3_uint8 *h)
813{
814 return h[0] == 0xff &&
815 ((h[1] & 0xF0) == 0xf0 || (h[1] & 0xFE) == 0xe2) &&
816 (DRMP3_HDR_GET_LAYER(h) != 0) &&
817 (DRMP3_HDR_GET_BITRATE(h) != 15) &&
818 (DRMP3_HDR_GET_SAMPLE_RATE(h) != 3);
819}
820
821static int drmp3_hdr_compare(const drmp3_uint8 *h1, const drmp3_uint8 *h2)
822{
823 return drmp3_hdr_valid(h2) &&
824 ((h1[1] ^ h2[1]) & 0xFE) == 0 &&
825 ((h1[2] ^ h2[2]) & 0x0C) == 0 &&
826 !(DRMP3_HDR_IS_FREE_FORMAT(h1) ^ DRMP3_HDR_IS_FREE_FORMAT(h2));
827}
828
829static unsigned drmp3_hdr_bitrate_kbps(const drmp3_uint8 *h)
830{
831 static const drmp3_uint8 halfrate[2][3][15] = {
832 { { 0,4,8,12,16,20,24,28,32,40,48,56,64,72,80 }, { 0,4,8,12,16,20,24,28,32,40,48,56,64,72,80 }, { 0,16,24,28,32,40,48,56,64,72,80,88,96,112,128 } },
833 { { 0,16,20,24,28,32,40,48,56,64,80,96,112,128,160 }, { 0,16,24,28,32,40,48,56,64,80,96,112,128,160,192 }, { 0,16,32,48,64,80,96,112,128,144,160,176,192,208,224 } },
834 };
835 return 2*halfrate[!!DRMP3_HDR_TEST_MPEG1(h)][DRMP3_HDR_GET_LAYER(h) - 1][DRMP3_HDR_GET_BITRATE(h)];
836}
837
838static unsigned drmp3_hdr_sample_rate_hz(const drmp3_uint8 *h)
839{
840 static const unsigned g_hz[3] = { 44100, 48000, 32000 };
841 return g_hz[DRMP3_HDR_GET_SAMPLE_RATE(h)] >> (int)!DRMP3_HDR_TEST_MPEG1(h) >> (int)!DRMP3_HDR_TEST_NOT_MPEG25(h);
842}
843
844static unsigned drmp3_hdr_frame_samples(const drmp3_uint8 *h)
845{
846 return DRMP3_HDR_IS_LAYER_1(h) ? 384 : (1152 >> (int)DRMP3_HDR_IS_FRAME_576(h));
847}
848
849static int drmp3_hdr_frame_bytes(const drmp3_uint8 *h, int free_format_size)
850{
851 int frame_bytes = drmp3_hdr_frame_samples(h)*drmp3_hdr_bitrate_kbps(h)*125/drmp3_hdr_sample_rate_hz(h);
852 if (DRMP3_HDR_IS_LAYER_1(h))
853 {
854 frame_bytes &= ~3; /* slot align */
855 }
856 return frame_bytes ? frame_bytes : free_format_size;
857}
858
859static int drmp3_hdr_padding(const drmp3_uint8 *h)
860{
861 return DRMP3_HDR_TEST_PADDING(h) ? (DRMP3_HDR_IS_LAYER_1(h) ? 4 : 1) : 0;
862}
863
864#ifndef DR_MP3_ONLY_MP3
865static const drmp3_L12_subband_alloc *drmp3_L12_subband_alloc_table(const drmp3_uint8 *hdr, drmp3_L12_scale_info *sci)
866{
867 const drmp3_L12_subband_alloc *alloc;
868 int mode = DRMP3_HDR_GET_STEREO_MODE(hdr);
869 int nbands, stereo_bands = (mode == DRMP3_MODE_MONO) ? 0 : (mode == DRMP3_MODE_JOINT_STEREO) ? (DRMP3_HDR_GET_STEREO_MODE_EXT(hdr) << 2) + 4 : 32;
870
871 if (DRMP3_HDR_IS_LAYER_1(hdr))
872 {
873 static const drmp3_L12_subband_alloc g_alloc_L1[] = { { 76, 4, 32 } };
874 alloc = g_alloc_L1;
875 nbands = 32;
876 } else if (!DRMP3_HDR_TEST_MPEG1(hdr))
877 {
878 static const drmp3_L12_subband_alloc g_alloc_L2M2[] = { { 60, 4, 4 }, { 44, 3, 7 }, { 44, 2, 19 } };
879 alloc = g_alloc_L2M2;
880 nbands = 30;
881 } else
882 {
883 static const drmp3_L12_subband_alloc g_alloc_L2M1[] = { { 0, 4, 3 }, { 16, 4, 8 }, { 32, 3, 12 }, { 40, 2, 7 } };
884 int sample_rate_idx = DRMP3_HDR_GET_SAMPLE_RATE(hdr);
885 unsigned kbps = drmp3_hdr_bitrate_kbps(hdr) >> (int)(mode != DRMP3_MODE_MONO);
886 if (!kbps) /* free-format */
887 {
888 kbps = 192;
889 }
890
891 alloc = g_alloc_L2M1;
892 nbands = 27;
893 if (kbps < 56)
894 {
895 static const drmp3_L12_subband_alloc g_alloc_L2M1_lowrate[] = { { 44, 4, 2 }, { 44, 3, 10 } };
896 alloc = g_alloc_L2M1_lowrate;
897 nbands = sample_rate_idx == 2 ? 12 : 8;
898 } else if (kbps >= 96 && sample_rate_idx != 1)
899 {
900 nbands = 30;
901 }
902 }
903
904 sci->total_bands = (drmp3_uint8)nbands;
905 sci->stereo_bands = (drmp3_uint8)DRMP3_MIN(stereo_bands, nbands);
906
907 return alloc;
908}
909
910static void drmp3_L12_read_scalefactors(drmp3_bs *bs, drmp3_uint8 *pba, drmp3_uint8 *scfcod, int bands, float *scf)
911{
912 static const float g_deq_L12[18*3] = {
913#define DRMP3_DQ(x) 9.53674316e-07f/x, 7.56931807e-07f/x, 6.00777173e-07f/x
914 DRMP3_DQ(3),DRMP3_DQ(7),DRMP3_DQ(15),DRMP3_DQ(31),DRMP3_DQ(63),DRMP3_DQ(127),DRMP3_DQ(255),DRMP3_DQ(511),DRMP3_DQ(1023),DRMP3_DQ(2047),DRMP3_DQ(4095),DRMP3_DQ(8191),DRMP3_DQ(16383),DRMP3_DQ(32767),DRMP3_DQ(65535),DRMP3_DQ(3),DRMP3_DQ(5),DRMP3_DQ(9)
915 };
916 int i, m;
917 for (i = 0; i < bands; i++)
918 {
919 float s = 0;
920 int ba = *pba++;
921 int mask = ba ? 4 + ((19 >> scfcod[i]) & 3) : 0;
922 for (m = 4; m; m >>= 1)
923 {
924 if (mask & m)
925 {
926 int b = drmp3_bs_get_bits(bs, 6);
927 s = g_deq_L12[ba*3 - 6 + b % 3]*(int)(1 << 21 >> b/3);
928 }
929 *scf++ = s;
930 }
931 }
932}
933
934static void drmp3_L12_read_scale_info(const drmp3_uint8 *hdr, drmp3_bs *bs, drmp3_L12_scale_info *sci)
935{
936 static const drmp3_uint8 g_bitalloc_code_tab[] = {
937 0,17, 3, 4, 5,6,7, 8,9,10,11,12,13,14,15,16,
938 0,17,18, 3,19,4,5, 6,7, 8, 9,10,11,12,13,16,
939 0,17,18, 3,19,4,5,16,
940 0,17,18,16,
941 0,17,18,19, 4,5,6, 7,8, 9,10,11,12,13,14,15,
942 0,17,18, 3,19,4,5, 6,7, 8, 9,10,11,12,13,14,
943 0, 2, 3, 4, 5,6,7, 8,9,10,11,12,13,14,15,16
944 };
945 const drmp3_L12_subband_alloc *subband_alloc = drmp3_L12_subband_alloc_table(hdr, sci);
946
947 int i, k = 0, ba_bits = 0;
948 const drmp3_uint8 *ba_code_tab = g_bitalloc_code_tab;
949
950 for (i = 0; i < sci->total_bands; i++)
951 {
952 drmp3_uint8 ba;
953 if (i == k)
954 {
955 k += subband_alloc->band_count;
956 ba_bits = subband_alloc->code_tab_width;
957 ba_code_tab = g_bitalloc_code_tab + subband_alloc->tab_offset;
958 subband_alloc++;
959 }
960 ba = ba_code_tab[drmp3_bs_get_bits(bs, ba_bits)];
961 sci->bitalloc[2*i] = ba;
962 if (i < sci->stereo_bands)
963 {
964 ba = ba_code_tab[drmp3_bs_get_bits(bs, ba_bits)];
965 }
966 sci->bitalloc[2*i + 1] = sci->stereo_bands ? ba : 0;
967 }
968
969 for (i = 0; i < 2*sci->total_bands; i++)
970 {
971 sci->scfcod[i] = (drmp3_uint8)(sci->bitalloc[i] ? DRMP3_HDR_IS_LAYER_1(hdr) ? 2 : drmp3_bs_get_bits(bs, 2) : 6);
972 }
973
974 drmp3_L12_read_scalefactors(bs, sci->bitalloc, sci->scfcod, sci->total_bands*2, sci->scf);
975
976 for (i = sci->stereo_bands; i < sci->total_bands; i++)
977 {
978 sci->bitalloc[2*i + 1] = 0;
979 }
980}
981
982static int drmp3_L12_dequantize_granule(float *grbuf, drmp3_bs *bs, drmp3_L12_scale_info *sci, int group_size)
983{
984 int i, j, k, choff = 576;
985 for (j = 0; j < 4; j++)
986 {
987 float *dst = grbuf + group_size*j;
988 for (i = 0; i < 2*sci->total_bands; i++)
989 {
990 int ba = sci->bitalloc[i];
991 if (ba != 0)
992 {
993 if (ba < 17)
994 {
995 int half = (1 << (ba - 1)) - 1;
996 for (k = 0; k < group_size; k++)
997 {
998 dst[k] = (float)((int)drmp3_bs_get_bits(bs, ba) - half);
999 }
1000 } else
1001 {
1002 unsigned mod = (2 << (ba - 17)) + 1; /* 3, 5, 9 */
1003 unsigned code = drmp3_bs_get_bits(bs, mod + 2 - (mod >> 3)); /* 5, 7, 10 */
1004 for (k = 0; k < group_size; k++, code /= mod)
1005 {
1006 dst[k] = (float)((int)(code % mod - mod/2));
1007 }
1008 }
1009 }
1010 dst += choff;
1011 choff = 18 - choff;
1012 }
1013 }
1014 return group_size*4;
1015}
1016
1017static void drmp3_L12_apply_scf_384(drmp3_L12_scale_info *sci, const float *scf, float *dst)
1018{
1019 int i, k;
1020 DRMP3_COPY_MEMORY(dst + 576 + sci->stereo_bands*18, dst + sci->stereo_bands*18, (sci->total_bands - sci->stereo_bands)*18*sizeof(float));
1021 for (i = 0; i < sci->total_bands; i++, dst += 18, scf += 6)
1022 {
1023 for (k = 0; k < 12; k++)
1024 {
1025 dst[k + 0] *= scf[0];
1026 dst[k + 576] *= scf[3];
1027 }
1028 }
1029}
1030#endif
1031
1032static int drmp3_L3_read_side_info(drmp3_bs *bs, drmp3_L3_gr_info *gr, const drmp3_uint8 *hdr)
1033{
1034 static const drmp3_uint8 g_scf_long[8][23] = {
1035 { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 },
1036 { 12,12,12,12,12,12,16,20,24,28,32,40,48,56,64,76,90,2,2,2,2,2,0 },
1037 { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 },
1038 { 6,6,6,6,6,6,8,10,12,14,16,18,22,26,32,38,46,54,62,70,76,36,0 },
1039 { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 },
1040 { 4,4,4,4,4,4,6,6,8,8,10,12,16,20,24,28,34,42,50,54,76,158,0 },
1041 { 4,4,4,4,4,4,6,6,6,8,10,12,16,18,22,28,34,40,46,54,54,192,0 },
1042 { 4,4,4,4,4,4,6,6,8,10,12,16,20,24,30,38,46,56,68,84,102,26,0 }
1043 };
1044 static const drmp3_uint8 g_scf_short[8][40] = {
1045 { 4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 },
1046 { 8,8,8,8,8,8,8,8,8,12,12,12,16,16,16,20,20,20,24,24,24,28,28,28,36,36,36,2,2,2,2,2,2,2,2,2,26,26,26,0 },
1047 { 4,4,4,4,4,4,4,4,4,6,6,6,6,6,6,8,8,8,10,10,10,14,14,14,18,18,18,26,26,26,32,32,32,42,42,42,18,18,18,0 },
1048 { 4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,32,32,32,44,44,44,12,12,12,0 },
1049 { 4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 },
1050 { 4,4,4,4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,22,22,22,30,30,30,56,56,56,0 },
1051 { 4,4,4,4,4,4,4,4,4,4,4,4,6,6,6,6,6,6,10,10,10,12,12,12,14,14,14,16,16,16,20,20,20,26,26,26,66,66,66,0 },
1052 { 4,4,4,4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,12,12,12,16,16,16,20,20,20,26,26,26,34,34,34,42,42,42,12,12,12,0 }
1053 };
1054 static const drmp3_uint8 g_scf_mixed[8][40] = {
1055 { 6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 },
1056 { 12,12,12,4,4,4,8,8,8,12,12,12,16,16,16,20,20,20,24,24,24,28,28,28,36,36,36,2,2,2,2,2,2,2,2,2,26,26,26,0 },
1057 { 6,6,6,6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,14,14,14,18,18,18,26,26,26,32,32,32,42,42,42,18,18,18,0 },
1058 { 6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,32,32,32,44,44,44,12,12,12,0 },
1059 { 6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 },
1060 { 4,4,4,4,4,4,6,6,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,22,22,22,30,30,30,56,56,56,0 },
1061 { 4,4,4,4,4,4,6,6,4,4,4,6,6,6,6,6,6,10,10,10,12,12,12,14,14,14,16,16,16,20,20,20,26,26,26,66,66,66,0 },
1062 { 4,4,4,4,4,4,6,6,4,4,4,6,6,6,8,8,8,12,12,12,16,16,16,20,20,20,26,26,26,34,34,34,42,42,42,12,12,12,0 }
1063 };
1064
1065 unsigned tables, scfsi = 0;
1066 int main_data_begin, part_23_sum = 0;
1067 int gr_count = DRMP3_HDR_IS_MONO(hdr) ? 1 : 2;
1068 int sr_idx = DRMP3_HDR_GET_MY_SAMPLE_RATE(hdr); sr_idx -= (sr_idx != 0);
1069
1070 if (DRMP3_HDR_TEST_MPEG1(hdr))
1071 {
1072 gr_count *= 2;
1073 main_data_begin = drmp3_bs_get_bits(bs, 9);
1074 scfsi = drmp3_bs_get_bits(bs, 7 + gr_count);
1075 } else
1076 {
1077 main_data_begin = drmp3_bs_get_bits(bs, 8 + gr_count) >> gr_count;
1078 }
1079
1080 do
1081 {
1082 if (DRMP3_HDR_IS_MONO(hdr))
1083 {
1084 scfsi <<= 4;
1085 }
1086 gr->part_23_length = (drmp3_uint16)drmp3_bs_get_bits(bs, 12);
1087 part_23_sum += gr->part_23_length;
1088 gr->big_values = (drmp3_uint16)drmp3_bs_get_bits(bs, 9);
1089 if (gr->big_values > 288)
1090 {
1091 return -1;
1092 }
1093 gr->global_gain = (drmp3_uint8)drmp3_bs_get_bits(bs, 8);
1094 gr->scalefac_compress = (drmp3_uint16)drmp3_bs_get_bits(bs, DRMP3_HDR_TEST_MPEG1(hdr) ? 4 : 9);
1095 gr->sfbtab = g_scf_long[sr_idx];
1096 gr->n_long_sfb = 22;
1097 gr->n_short_sfb = 0;
1098 if (drmp3_bs_get_bits(bs, 1))
1099 {
1100 gr->block_type = (drmp3_uint8)drmp3_bs_get_bits(bs, 2);
1101 if (!gr->block_type)
1102 {
1103 return -1;
1104 }
1105 gr->mixed_block_flag = (drmp3_uint8)drmp3_bs_get_bits(bs, 1);
1106 gr->region_count[0] = 7;
1107 gr->region_count[1] = 255;
1108 if (gr->block_type == DRMP3_SHORT_BLOCK_TYPE)
1109 {
1110 scfsi &= 0x0F0F;
1111 if (!gr->mixed_block_flag)
1112 {
1113 gr->region_count[0] = 8;
1114 gr->sfbtab = g_scf_short[sr_idx];
1115 gr->n_long_sfb = 0;
1116 gr->n_short_sfb = 39;
1117 } else
1118 {
1119 gr->sfbtab = g_scf_mixed[sr_idx];
1120 gr->n_long_sfb = DRMP3_HDR_TEST_MPEG1(hdr) ? 8 : 6;
1121 gr->n_short_sfb = 30;
1122 }
1123 }
1124 tables = drmp3_bs_get_bits(bs, 10);
1125 tables <<= 5;
1126 gr->subblock_gain[0] = (drmp3_uint8)drmp3_bs_get_bits(bs, 3);
1127 gr->subblock_gain[1] = (drmp3_uint8)drmp3_bs_get_bits(bs, 3);
1128 gr->subblock_gain[2] = (drmp3_uint8)drmp3_bs_get_bits(bs, 3);
1129 } else
1130 {
1131 gr->block_type = 0;
1132 gr->mixed_block_flag = 0;
1133 tables = drmp3_bs_get_bits(bs, 15);
1134 gr->region_count[0] = (drmp3_uint8)drmp3_bs_get_bits(bs, 4);
1135 gr->region_count[1] = (drmp3_uint8)drmp3_bs_get_bits(bs, 3);
1136 gr->region_count[2] = 255;
1137 }
1138 gr->table_select[0] = (drmp3_uint8)(tables >> 10);
1139 gr->table_select[1] = (drmp3_uint8)((tables >> 5) & 31);
1140 gr->table_select[2] = (drmp3_uint8)((tables) & 31);
1141 gr->preflag = (drmp3_uint8)(DRMP3_HDR_TEST_MPEG1(hdr) ? drmp3_bs_get_bits(bs, 1) : (gr->scalefac_compress >= 500));
1142 gr->scalefac_scale = (drmp3_uint8)drmp3_bs_get_bits(bs, 1);
1143 gr->count1_table = (drmp3_uint8)drmp3_bs_get_bits(bs, 1);
1144 gr->scfsi = (drmp3_uint8)((scfsi >> 12) & 15);
1145 scfsi <<= 4;
1146 gr++;
1147 } while(--gr_count);
1148
1149 if (part_23_sum + bs->pos > bs->limit + main_data_begin*8)
1150 {
1151 return -1;
1152 }
1153
1154 return main_data_begin;
1155}
1156
1157static void drmp3_L3_read_scalefactors(drmp3_uint8 *scf, drmp3_uint8 *ist_pos, const drmp3_uint8 *scf_size, const drmp3_uint8 *scf_count, drmp3_bs *bitbuf, int scfsi)
1158{
1159 int i, k;
1160 for (i = 0; i < 4 && scf_count[i]; i++, scfsi *= 2)
1161 {
1162 int cnt = scf_count[i];
1163 if (scfsi & 8)
1164 {
1165 DRMP3_COPY_MEMORY(scf, ist_pos, cnt);
1166 } else
1167 {
1168 int bits = scf_size[i];
1169 if (!bits)
1170 {
1171 DRMP3_ZERO_MEMORY(scf, cnt);
1172 DRMP3_ZERO_MEMORY(ist_pos, cnt);
1173 } else
1174 {
1175 int max_scf = (scfsi < 0) ? (1 << bits) - 1 : -1;
1176 for (k = 0; k < cnt; k++)
1177 {
1178 int s = drmp3_bs_get_bits(bitbuf, bits);
1179 ist_pos[k] = (drmp3_uint8)(s == max_scf ? -1 : s);
1180 scf[k] = (drmp3_uint8)s;
1181 }
1182 }
1183 }
1184 ist_pos += cnt;
1185 scf += cnt;
1186 }
1187 scf[0] = scf[1] = scf[2] = 0;
1188}
1189
1190static float drmp3_L3_ldexp_q2(float y, int exp_q2)
1191{
1192 static const float g_expfrac[4] = { 9.31322575e-10f,7.83145814e-10f,6.58544508e-10f,5.53767716e-10f };
1193 int e;
1194 do
1195 {
1196 e = DRMP3_MIN(30*4, exp_q2);
1197 y *= g_expfrac[e & 3]*(1 << 30 >> (e >> 2));
1198 } while ((exp_q2 -= e) > 0);
1199 return y;
1200}
1201
1202static void drmp3_L3_decode_scalefactors(const drmp3_uint8 *hdr, drmp3_uint8 *ist_pos, drmp3_bs *bs, const drmp3_L3_gr_info *gr, float *scf, int ch)
1203{
1204 static const drmp3_uint8 g_scf_partitions[3][28] = {
1205 { 6,5,5, 5,6,5,5,5,6,5, 7,3,11,10,0,0, 7, 7, 7,0, 6, 6,6,3, 8, 8,5,0 },
1206 { 8,9,6,12,6,9,9,9,6,9,12,6,15,18,0,0, 6,15,12,0, 6,12,9,6, 6,18,9,0 },
1207 { 9,9,6,12,9,9,9,9,9,9,12,6,18,18,0,0,12,12,12,0,12, 9,9,6,15,12,9,0 }
1208 };
1209 const drmp3_uint8 *scf_partition = g_scf_partitions[!!gr->n_short_sfb + !gr->n_long_sfb];
1210 drmp3_uint8 scf_size[4], iscf[40];
1211 int i, scf_shift = gr->scalefac_scale + 1, gain_exp, scfsi = gr->scfsi;
1212 float gain;
1213
1214 if (DRMP3_HDR_TEST_MPEG1(hdr))
1215 {
1216 static const drmp3_uint8 g_scfc_decode[16] = { 0,1,2,3, 12,5,6,7, 9,10,11,13, 14,15,18,19 };
1217 int part = g_scfc_decode[gr->scalefac_compress];
1218 scf_size[1] = scf_size[0] = (drmp3_uint8)(part >> 2);
1219 scf_size[3] = scf_size[2] = (drmp3_uint8)(part & 3);
1220 } else
1221 {
1222 static const drmp3_uint8 g_mod[6*4] = { 5,5,4,4,5,5,4,1,4,3,1,1,5,6,6,1,4,4,4,1,4,3,1,1 };
1223 int k, modprod, sfc, ist = DRMP3_HDR_TEST_I_STEREO(hdr) && ch;
1224 sfc = gr->scalefac_compress >> ist;
1225 for (k = ist*3*4; sfc >= 0; sfc -= modprod, k += 4)
1226 {
1227 for (modprod = 1, i = 3; i >= 0; i--)
1228 {
1229 scf_size[i] = (drmp3_uint8)(sfc / modprod % g_mod[k + i]);
1230 modprod *= g_mod[k + i];
1231 }
1232 }
1233 scf_partition += k;
1234 scfsi = -16;
1235 }
1236 drmp3_L3_read_scalefactors(iscf, ist_pos, scf_size, scf_partition, bs, scfsi);
1237
1238 if (gr->n_short_sfb)
1239 {
1240 int sh = 3 - scf_shift;
1241 for (i = 0; i < gr->n_short_sfb; i += 3)
1242 {
1243 iscf[gr->n_long_sfb + i + 0] = (drmp3_uint8)(iscf[gr->n_long_sfb + i + 0] + (gr->subblock_gain[0] << sh));
1244 iscf[gr->n_long_sfb + i + 1] = (drmp3_uint8)(iscf[gr->n_long_sfb + i + 1] + (gr->subblock_gain[1] << sh));
1245 iscf[gr->n_long_sfb + i + 2] = (drmp3_uint8)(iscf[gr->n_long_sfb + i + 2] + (gr->subblock_gain[2] << sh));
1246 }
1247 } else if (gr->preflag)
1248 {
1249 static const drmp3_uint8 g_preamp[10] = { 1,1,1,1,2,2,3,3,3,2 };
1250 for (i = 0; i < 10; i++)
1251 {
1252 iscf[11 + i] = (drmp3_uint8)(iscf[11 + i] + g_preamp[i]);
1253 }
1254 }
1255
1256 gain_exp = gr->global_gain + DRMP3_BITS_DEQUANTIZER_OUT*4 - 210 - (DRMP3_HDR_IS_MS_STEREO(hdr) ? 2 : 0);
1257 gain = drmp3_L3_ldexp_q2(1 << (DRMP3_MAX_SCFI/4), DRMP3_MAX_SCFI - gain_exp);
1258 for (i = 0; i < (int)(gr->n_long_sfb + gr->n_short_sfb); i++)
1259 {
1260 scf[i] = drmp3_L3_ldexp_q2(gain, iscf[i] << scf_shift);
1261 }
1262}
1263
1264static const float g_drmp3_pow43[129 + 16] = {
1265 0,-1,-2.519842f,-4.326749f,-6.349604f,-8.549880f,-10.902724f,-13.390518f,-16.000000f,-18.720754f,-21.544347f,-24.463781f,-27.473142f,-30.567351f,-33.741992f,-36.993181f,
1266 0,1,2.519842f,4.326749f,6.349604f,8.549880f,10.902724f,13.390518f,16.000000f,18.720754f,21.544347f,24.463781f,27.473142f,30.567351f,33.741992f,36.993181f,40.317474f,43.711787f,47.173345f,50.699631f,54.288352f,57.937408f,61.644865f,65.408941f,69.227979f,73.100443f,77.024898f,81.000000f,85.024491f,89.097188f,93.216975f,97.382800f,101.593667f,105.848633f,110.146801f,114.487321f,118.869381f,123.292209f,127.755065f,132.257246f,136.798076f,141.376907f,145.993119f,150.646117f,155.335327f,160.060199f,164.820202f,169.614826f,174.443577f,179.305980f,184.201575f,189.129918f,194.090580f,199.083145f,204.107210f,209.162385f,214.248292f,219.364564f,224.510845f,229.686789f,234.892058f,240.126328f,245.389280f,250.680604f,256.000000f,261.347174f,266.721841f,272.123723f,277.552547f,283.008049f,288.489971f,293.998060f,299.532071f,305.091761f,310.676898f,316.287249f,321.922592f,327.582707f,333.267377f,338.976394f,344.709550f,350.466646f,356.247482f,362.051866f,367.879608f,373.730522f,379.604427f,385.501143f,391.420496f,397.362314f,403.326427f,409.312672f,415.320884f,421.350905f,427.402579f,433.475750f,439.570269f,445.685987f,451.822757f,457.980436f,464.158883f,470.357960f,476.577530f,482.817459f,489.077615f,495.357868f,501.658090f,507.978156f,514.317941f,520.677324f,527.056184f,533.454404f,539.871867f,546.308458f,552.764065f,559.238575f,565.731879f,572.243870f,578.774440f,585.323483f,591.890898f,598.476581f,605.080431f,611.702349f,618.342238f,625.000000f,631.675540f,638.368763f,645.079578f
1267};
1268
1269static float drmp3_L3_pow_43(int x)
1270{
1271 float frac;
1272 int sign, mult = 256;
1273
1274 if (x < 129)
1275 {
1276 return g_drmp3_pow43[16 + x];
1277 }
1278
1279 if (x < 1024)
1280 {
1281 mult = 16;
1282 x <<= 3;
1283 }
1284
1285 sign = 2*x & 64;
1286 frac = (float)((x & 63) - sign) / ((x & ~63) + sign);
1287 return g_drmp3_pow43[16 + ((x + sign) >> 6)]*(1.f + frac*((4.f/3) + frac*(2.f/9)))*mult;
1288}
1289
1290static void drmp3_L3_huffman(float *dst, drmp3_bs *bs, const drmp3_L3_gr_info *gr_info, const float *scf, int layer3gr_limit)
1291{
1292 static const drmp3_int16 tabs[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1293 785,785,785,785,784,784,784,784,513,513,513,513,513,513,513,513,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,
1294 -255,1313,1298,1282,785,785,785,785,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,290,288,
1295 -255,1313,1298,1282,769,769,769,769,529,529,529,529,529,529,529,529,528,528,528,528,528,528,528,528,512,512,512,512,512,512,512,512,290,288,
1296 -253,-318,-351,-367,785,785,785,785,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,819,818,547,547,275,275,275,275,561,560,515,546,289,274,288,258,
1297 -254,-287,1329,1299,1314,1312,1057,1057,1042,1042,1026,1026,784,784,784,784,529,529,529,529,529,529,529,529,769,769,769,769,768,768,768,768,563,560,306,306,291,259,
1298 -252,-413,-477,-542,1298,-575,1041,1041,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-383,-399,1107,1092,1106,1061,849,849,789,789,1104,1091,773,773,1076,1075,341,340,325,309,834,804,577,577,532,532,516,516,832,818,803,816,561,561,531,531,515,546,289,289,288,258,
1299 -252,-429,-493,-559,1057,1057,1042,1042,529,529,529,529,529,529,529,529,784,784,784,784,769,769,769,769,512,512,512,512,512,512,512,512,-382,1077,-415,1106,1061,1104,849,849,789,789,1091,1076,1029,1075,834,834,597,581,340,340,339,324,804,833,532,532,832,772,818,803,817,787,816,771,290,290,290,290,288,258,
1300 -253,-349,-414,-447,-463,1329,1299,-479,1314,1312,1057,1057,1042,1042,1026,1026,785,785,785,785,784,784,784,784,769,769,769,769,768,768,768,768,-319,851,821,-335,836,850,805,849,341,340,325,336,533,533,579,579,564,564,773,832,578,548,563,516,321,276,306,291,304,259,
1301 -251,-572,-733,-830,-863,-879,1041,1041,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-511,-527,-543,1396,1351,1381,1366,1395,1335,1380,-559,1334,1138,1138,1063,1063,1350,1392,1031,1031,1062,1062,1364,1363,1120,1120,1333,1348,881,881,881,881,375,374,359,373,343,358,341,325,791,791,1123,1122,-703,1105,1045,-719,865,865,790,790,774,774,1104,1029,338,293,323,308,-799,-815,833,788,772,818,803,816,322,292,307,320,561,531,515,546,289,274,288,258,
1302 -251,-525,-605,-685,-765,-831,-846,1298,1057,1057,1312,1282,785,785,785,785,784,784,784,784,769,769,769,769,512,512,512,512,512,512,512,512,1399,1398,1383,1367,1382,1396,1351,-511,1381,1366,1139,1139,1079,1079,1124,1124,1364,1349,1363,1333,882,882,882,882,807,807,807,807,1094,1094,1136,1136,373,341,535,535,881,775,867,822,774,-591,324,338,-671,849,550,550,866,864,609,609,293,336,534,534,789,835,773,-751,834,804,308,307,833,788,832,772,562,562,547,547,305,275,560,515,290,290,
1303 -252,-397,-477,-557,-622,-653,-719,-735,-750,1329,1299,1314,1057,1057,1042,1042,1312,1282,1024,1024,785,785,785,785,784,784,784,784,769,769,769,769,-383,1127,1141,1111,1126,1140,1095,1110,869,869,883,883,1079,1109,882,882,375,374,807,868,838,881,791,-463,867,822,368,263,852,837,836,-543,610,610,550,550,352,336,534,534,865,774,851,821,850,805,593,533,579,564,773,832,578,578,548,548,577,577,307,276,306,291,516,560,259,259,
1304 -250,-2107,-2507,-2764,-2909,-2974,-3007,-3023,1041,1041,1040,1040,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-767,-1052,-1213,-1277,-1358,-1405,-1469,-1535,-1550,-1582,-1614,-1647,-1662,-1694,-1726,-1759,-1774,-1807,-1822,-1854,-1886,1565,-1919,-1935,-1951,-1967,1731,1730,1580,1717,-1983,1729,1564,-1999,1548,-2015,-2031,1715,1595,-2047,1714,-2063,1610,-2079,1609,-2095,1323,1323,1457,1457,1307,1307,1712,1547,1641,1700,1699,1594,1685,1625,1442,1442,1322,1322,-780,-973,-910,1279,1278,1277,1262,1276,1261,1275,1215,1260,1229,-959,974,974,989,989,-943,735,478,478,495,463,506,414,-1039,1003,958,1017,927,942,987,957,431,476,1272,1167,1228,-1183,1256,-1199,895,895,941,941,1242,1227,1212,1135,1014,1014,490,489,503,487,910,1013,985,925,863,894,970,955,1012,847,-1343,831,755,755,984,909,428,366,754,559,-1391,752,486,457,924,997,698,698,983,893,740,740,908,877,739,739,667,667,953,938,497,287,271,271,683,606,590,712,726,574,302,302,738,736,481,286,526,725,605,711,636,724,696,651,589,681,666,710,364,467,573,695,466,466,301,465,379,379,709,604,665,679,316,316,634,633,436,436,464,269,424,394,452,332,438,363,347,408,393,448,331,422,362,407,392,421,346,406,391,376,375,359,1441,1306,-2367,1290,-2383,1337,-2399,-2415,1426,1321,-2431,1411,1336,-2447,-2463,-2479,1169,1169,1049,1049,1424,1289,1412,1352,1319,-2495,1154,1154,1064,1064,1153,1153,416,390,360,404,403,389,344,374,373,343,358,372,327,357,342,311,356,326,1395,1394,1137,1137,1047,1047,1365,1392,1287,1379,1334,1364,1349,1378,1318,1363,792,792,792,792,1152,1152,1032,1032,1121,1121,1046,1046,1120,1120,1030,1030,-2895,1106,1061,1104,849,849,789,789,1091,1076,1029,1090,1060,1075,833,833,309,324,532,532,832,772,818,803,561,561,531,560,515,546,289,274,288,258,
1305 -250,-1179,-1579,-1836,-1996,-2124,-2253,-2333,-2413,-2477,-2542,-2574,-2607,-2622,-2655,1314,1313,1298,1312,1282,785,785,785,785,1040,1040,1025,1025,768,768,768,768,-766,-798,-830,-862,-895,-911,-927,-943,-959,-975,-991,-1007,-1023,-1039,-1055,-1070,1724,1647,-1103,-1119,1631,1767,1662,1738,1708,1723,-1135,1780,1615,1779,1599,1677,1646,1778,1583,-1151,1777,1567,1737,1692,1765,1722,1707,1630,1751,1661,1764,1614,1736,1676,1763,1750,1645,1598,1721,1691,1762,1706,1582,1761,1566,-1167,1749,1629,767,766,751,765,494,494,735,764,719,749,734,763,447,447,748,718,477,506,431,491,446,476,461,505,415,430,475,445,504,399,460,489,414,503,383,474,429,459,502,502,746,752,488,398,501,473,413,472,486,271,480,270,-1439,-1455,1357,-1471,-1487,-1503,1341,1325,-1519,1489,1463,1403,1309,-1535,1372,1448,1418,1476,1356,1462,1387,-1551,1475,1340,1447,1402,1386,-1567,1068,1068,1474,1461,455,380,468,440,395,425,410,454,364,467,466,464,453,269,409,448,268,432,1371,1473,1432,1417,1308,1460,1355,1446,1459,1431,1083,1083,1401,1416,1458,1445,1067,1067,1370,1457,1051,1051,1291,1430,1385,1444,1354,1415,1400,1443,1082,1082,1173,1113,1186,1066,1185,1050,-1967,1158,1128,1172,1097,1171,1081,-1983,1157,1112,416,266,375,400,1170,1142,1127,1065,793,793,1169,1033,1156,1096,1141,1111,1155,1080,1126,1140,898,898,808,808,897,897,792,792,1095,1152,1032,1125,1110,1139,1079,1124,882,807,838,881,853,791,-2319,867,368,263,822,852,837,866,806,865,-2399,851,352,262,534,534,821,836,594,594,549,549,593,593,533,533,848,773,579,579,564,578,548,563,276,276,577,576,306,291,516,560,305,305,275,259,
1306 -251,-892,-2058,-2620,-2828,-2957,-3023,-3039,1041,1041,1040,1040,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-511,-527,-543,-559,1530,-575,-591,1528,1527,1407,1526,1391,1023,1023,1023,1023,1525,1375,1268,1268,1103,1103,1087,1087,1039,1039,1523,-604,815,815,815,815,510,495,509,479,508,463,507,447,431,505,415,399,-734,-782,1262,-815,1259,1244,-831,1258,1228,-847,-863,1196,-879,1253,987,987,748,-767,493,493,462,477,414,414,686,669,478,446,461,445,474,429,487,458,412,471,1266,1264,1009,1009,799,799,-1019,-1276,-1452,-1581,-1677,-1757,-1821,-1886,-1933,-1997,1257,1257,1483,1468,1512,1422,1497,1406,1467,1496,1421,1510,1134,1134,1225,1225,1466,1451,1374,1405,1252,1252,1358,1480,1164,1164,1251,1251,1238,1238,1389,1465,-1407,1054,1101,-1423,1207,-1439,830,830,1248,1038,1237,1117,1223,1148,1236,1208,411,426,395,410,379,269,1193,1222,1132,1235,1221,1116,976,976,1192,1162,1177,1220,1131,1191,963,963,-1647,961,780,-1663,558,558,994,993,437,408,393,407,829,978,813,797,947,-1743,721,721,377,392,844,950,828,890,706,706,812,859,796,960,948,843,934,874,571,571,-1919,690,555,689,421,346,539,539,944,779,918,873,932,842,903,888,570,570,931,917,674,674,-2575,1562,-2591,1609,-2607,1654,1322,1322,1441,1441,1696,1546,1683,1593,1669,1624,1426,1426,1321,1321,1639,1680,1425,1425,1305,1305,1545,1668,1608,1623,1667,1592,1638,1666,1320,1320,1652,1607,1409,1409,1304,1304,1288,1288,1664,1637,1395,1395,1335,1335,1622,1636,1394,1394,1319,1319,1606,1621,1392,1392,1137,1137,1137,1137,345,390,360,375,404,373,1047,-2751,-2767,-2783,1062,1121,1046,-2799,1077,-2815,1106,1061,789,789,1105,1104,263,355,310,340,325,354,352,262,339,324,1091,1076,1029,1090,1060,1075,833,833,788,788,1088,1028,818,818,803,803,561,561,531,531,816,771,546,546,289,274,288,258,
1307 -253,-317,-381,-446,-478,-509,1279,1279,-811,-1179,-1451,-1756,-1900,-2028,-2189,-2253,-2333,-2414,-2445,-2511,-2526,1313,1298,-2559,1041,1041,1040,1040,1025,1025,1024,1024,1022,1007,1021,991,1020,975,1019,959,687,687,1018,1017,671,671,655,655,1016,1015,639,639,758,758,623,623,757,607,756,591,755,575,754,559,543,543,1009,783,-575,-621,-685,-749,496,-590,750,749,734,748,974,989,1003,958,988,973,1002,942,987,957,972,1001,926,986,941,971,956,1000,910,985,925,999,894,970,-1071,-1087,-1102,1390,-1135,1436,1509,1451,1374,-1151,1405,1358,1480,1420,-1167,1507,1494,1389,1342,1465,1435,1450,1326,1505,1310,1493,1373,1479,1404,1492,1464,1419,428,443,472,397,736,526,464,464,486,457,442,471,484,482,1357,1449,1434,1478,1388,1491,1341,1490,1325,1489,1463,1403,1309,1477,1372,1448,1418,1433,1476,1356,1462,1387,-1439,1475,1340,1447,1402,1474,1324,1461,1371,1473,269,448,1432,1417,1308,1460,-1711,1459,-1727,1441,1099,1099,1446,1386,1431,1401,-1743,1289,1083,1083,1160,1160,1458,1445,1067,1067,1370,1457,1307,1430,1129,1129,1098,1098,268,432,267,416,266,400,-1887,1144,1187,1082,1173,1113,1186,1066,1050,1158,1128,1143,1172,1097,1171,1081,420,391,1157,1112,1170,1142,1127,1065,1169,1049,1156,1096,1141,1111,1155,1080,1126,1154,1064,1153,1140,1095,1048,-2159,1125,1110,1137,-2175,823,823,1139,1138,807,807,384,264,368,263,868,838,853,791,867,822,852,837,866,806,865,790,-2319,851,821,836,352,262,850,805,849,-2399,533,533,835,820,336,261,578,548,563,577,532,532,832,772,562,562,547,547,305,275,560,515,290,290,288,258 };
1308 static const drmp3_uint8 tab32[] = { 130,162,193,209,44,28,76,140,9,9,9,9,9,9,9,9,190,254,222,238,126,94,157,157,109,61,173,205};
1309 static const drmp3_uint8 tab33[] = { 252,236,220,204,188,172,156,140,124,108,92,76,60,44,28,12 };
1310 static const drmp3_int16 tabindex[2*16] = { 0,32,64,98,0,132,180,218,292,364,426,538,648,746,0,1126,1460,1460,1460,1460,1460,1460,1460,1460,1842,1842,1842,1842,1842,1842,1842,1842 };
1311 static const drmp3_uint8 g_linbits[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,6,8,10,13,4,5,6,7,8,9,11,13 };
1312
1313#define DRMP3_PEEK_BITS(n) (bs_cache >> (32 - (n)))
1314#define DRMP3_FLUSH_BITS(n) { bs_cache <<= (n); bs_sh += (n); }
1315#define DRMP3_CHECK_BITS while (bs_sh >= 0) { bs_cache |= (drmp3_uint32)*bs_next_ptr++ << bs_sh; bs_sh -= 8; }
1316#define DRMP3_BSPOS ((bs_next_ptr - bs->buf)*8 - 24 + bs_sh)
1317
1318 float one = 0.0f;
1319 int ireg = 0, big_val_cnt = gr_info->big_values;
1320 const drmp3_uint8 *sfb = gr_info->sfbtab;
1321 const drmp3_uint8 *bs_next_ptr = bs->buf + bs->pos/8;
1322 drmp3_uint32 bs_cache = (((bs_next_ptr[0]*256u + bs_next_ptr[1])*256u + bs_next_ptr[2])*256u + bs_next_ptr[3]) << (bs->pos & 7);
1323 int pairs_to_decode, np, bs_sh = (bs->pos & 7) - 8;
1324 bs_next_ptr += 4;
1325
1326 while (big_val_cnt > 0)
1327 {
1328 int tab_num = gr_info->table_select[ireg];
1329 int sfb_cnt = gr_info->region_count[ireg++];
1330 const drmp3_int16 *codebook = tabs + tabindex[tab_num];
1331 int linbits = g_linbits[tab_num];
1332 if (linbits)
1333 {
1334 do
1335 {
1336 np = *sfb++ / 2;
1337 pairs_to_decode = DRMP3_MIN(big_val_cnt, np);
1338 one = *scf++;
1339 do
1340 {
1341 int j, w = 5;
1342 int leaf = codebook[DRMP3_PEEK_BITS(w)];
1343 while (leaf < 0)
1344 {
1345 DRMP3_FLUSH_BITS(w);
1346 w = leaf & 7;
1347 leaf = codebook[DRMP3_PEEK_BITS(w) - (leaf >> 3)];
1348 }
1349 DRMP3_FLUSH_BITS(leaf >> 8);
1350
1351 for (j = 0; j < 2; j++, dst++, leaf >>= 4)
1352 {
1353 int lsb = leaf & 0x0F;
1354 if (lsb == 15)
1355 {
1356 lsb += DRMP3_PEEK_BITS(linbits);
1357 DRMP3_FLUSH_BITS(linbits);
1358 DRMP3_CHECK_BITS;
1359 *dst = one*drmp3_L3_pow_43(lsb)*((drmp3_int32)bs_cache < 0 ? -1: 1);
1360 } else
1361 {
1362 *dst = g_drmp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one;
1363 }
1364 DRMP3_FLUSH_BITS(lsb ? 1 : 0);
1365 }
1366 DRMP3_CHECK_BITS;
1367 } while (--pairs_to_decode);
1368 } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0);
1369 } else
1370 {
1371 do
1372 {
1373 np = *sfb++ / 2;
1374 pairs_to_decode = DRMP3_MIN(big_val_cnt, np);
1375 one = *scf++;
1376 do
1377 {
1378 int j, w = 5;
1379 int leaf = codebook[DRMP3_PEEK_BITS(w)];
1380 while (leaf < 0)
1381 {
1382 DRMP3_FLUSH_BITS(w);
1383 w = leaf & 7;
1384 leaf = codebook[DRMP3_PEEK_BITS(w) - (leaf >> 3)];
1385 }
1386 DRMP3_FLUSH_BITS(leaf >> 8);
1387
1388 for (j = 0; j < 2; j++, dst++, leaf >>= 4)
1389 {
1390 int lsb = leaf & 0x0F;
1391 *dst = g_drmp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one;
1392 DRMP3_FLUSH_BITS(lsb ? 1 : 0);
1393 }
1394 DRMP3_CHECK_BITS;
1395 } while (--pairs_to_decode);
1396 } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0);
1397 }
1398 }
1399
1400 for (np = 1 - big_val_cnt;; dst += 4)
1401 {
1402 const drmp3_uint8 *codebook_count1 = (gr_info->count1_table) ? tab33 : tab32;
1403 int leaf = codebook_count1[DRMP3_PEEK_BITS(4)];
1404 if (!(leaf & 8))
1405 {
1406 leaf = codebook_count1[(leaf >> 3) + (bs_cache << 4 >> (32 - (leaf & 3)))];
1407 }
1408 DRMP3_FLUSH_BITS(leaf & 7);
1409 if (DRMP3_BSPOS > layer3gr_limit)
1410 {
1411 break;
1412 }
1413#define DRMP3_RELOAD_SCALEFACTOR if (!--np) { np = *sfb++/2; if (!np) break; one = *scf++; }
1414#define DRMP3_DEQ_COUNT1(s) if (leaf & (128 >> s)) { dst[s] = ((drmp3_int32)bs_cache < 0) ? -one : one; DRMP3_FLUSH_BITS(1) }
1415 DRMP3_RELOAD_SCALEFACTOR;
1416 DRMP3_DEQ_COUNT1(0);
1417 DRMP3_DEQ_COUNT1(1);
1418 DRMP3_RELOAD_SCALEFACTOR;
1419 DRMP3_DEQ_COUNT1(2);
1420 DRMP3_DEQ_COUNT1(3);
1421 DRMP3_CHECK_BITS;
1422 }
1423
1424 bs->pos = layer3gr_limit;
1425}
1426
1427static void drmp3_L3_midside_stereo(float *left, int n)
1428{
1429 int i = 0;
1430 float *right = left + 576;
1431#if DRMP3_HAVE_SIMD
1432 if (drmp3_have_simd())
1433 {
1434 for (; i < n - 3; i += 4)
1435 {
1436 drmp3_f4 vl = DRMP3_VLD(left + i);
1437 drmp3_f4 vr = DRMP3_VLD(right + i);
1438 DRMP3_VSTORE(left + i, DRMP3_VADD(vl, vr));
1439 DRMP3_VSTORE(right + i, DRMP3_VSUB(vl, vr));
1440 }
1441#ifdef __GNUC__
1442 /* Workaround for spurious -Waggressive-loop-optimizations warning from gcc.
1443 * For more info see: https://github.com/lieff/minimp3/issues/88
1444 */
1445 if (__builtin_constant_p(n % 4 == 0) && n % 4 == 0)
1446 return;
1447#endif
1448 }
1449#endif
1450 for (; i < n; i++)
1451 {
1452 float a = left[i];
1453 float b = right[i];
1454 left[i] = a + b;
1455 right[i] = a - b;
1456 }
1457}
1458
1459static void drmp3_L3_intensity_stereo_band(float *left, int n, float kl, float kr)
1460{
1461 int i;
1462 for (i = 0; i < n; i++)
1463 {
1464 left[i + 576] = left[i]*kr;
1465 left[i] = left[i]*kl;
1466 }
1467}
1468
1469static void drmp3_L3_stereo_top_band(const float *right, const drmp3_uint8 *sfb, int nbands, int max_band[3])
1470{
1471 int i, k;
1472
1473 max_band[0] = max_band[1] = max_band[2] = -1;
1474
1475 for (i = 0; i < nbands; i++)
1476 {
1477 for (k = 0; k < sfb[i]; k += 2)
1478 {
1479 if (right[k] != 0 || right[k + 1] != 0)
1480 {
1481 max_band[i % 3] = i;
1482 break;
1483 }
1484 }
1485 right += sfb[i];
1486 }
1487}
1488
1489static void drmp3_L3_stereo_process(float *left, const drmp3_uint8 *ist_pos, const drmp3_uint8 *sfb, const drmp3_uint8 *hdr, int max_band[3], int mpeg2_sh)
1490{
1491 static const float g_pan[7*2] = { 0,1,0.21132487f,0.78867513f,0.36602540f,0.63397460f,0.5f,0.5f,0.63397460f,0.36602540f,0.78867513f,0.21132487f,1,0 };
1492 unsigned i, max_pos = DRMP3_HDR_TEST_MPEG1(hdr) ? 7 : 64;
1493
1494 for (i = 0; sfb[i]; i++)
1495 {
1496 unsigned ipos = ist_pos[i];
1497 if ((int)i > max_band[i % 3] && ipos < max_pos)
1498 {
1499 float kl, kr, s = DRMP3_HDR_TEST_MS_STEREO(hdr) ? 1.41421356f : 1;
1500 if (DRMP3_HDR_TEST_MPEG1(hdr))
1501 {
1502 kl = g_pan[2*ipos];
1503 kr = g_pan[2*ipos + 1];
1504 } else
1505 {
1506 kl = 1;
1507 kr = drmp3_L3_ldexp_q2(1, (ipos + 1) >> 1 << mpeg2_sh);
1508 if (ipos & 1)
1509 {
1510 kl = kr;
1511 kr = 1;
1512 }
1513 }
1514 drmp3_L3_intensity_stereo_band(left, sfb[i], kl*s, kr*s);
1515 } else if (DRMP3_HDR_TEST_MS_STEREO(hdr))
1516 {
1517 drmp3_L3_midside_stereo(left, sfb[i]);
1518 }
1519 left += sfb[i];
1520 }
1521}
1522
1523static void drmp3_L3_intensity_stereo(float *left, drmp3_uint8 *ist_pos, const drmp3_L3_gr_info *gr, const drmp3_uint8 *hdr)
1524{
1525 int max_band[3], n_sfb = gr->n_long_sfb + gr->n_short_sfb;
1526 int i, max_blocks = gr->n_short_sfb ? 3 : 1;
1527
1528 drmp3_L3_stereo_top_band(left + 576, gr->sfbtab, n_sfb, max_band);
1529 if (gr->n_long_sfb)
1530 {
1531 max_band[0] = max_band[1] = max_band[2] = DRMP3_MAX(DRMP3_MAX(max_band[0], max_band[1]), max_band[2]);
1532 }
1533 for (i = 0; i < max_blocks; i++)
1534 {
1535 int default_pos = DRMP3_HDR_TEST_MPEG1(hdr) ? 3 : 0;
1536 int itop = n_sfb - max_blocks + i;
1537 int prev = itop - max_blocks;
1538 ist_pos[itop] = (drmp3_uint8)(max_band[i] >= prev ? default_pos : ist_pos[prev]);
1539 }
1540 drmp3_L3_stereo_process(left, ist_pos, gr->sfbtab, hdr, max_band, gr[1].scalefac_compress & 1);
1541}
1542
1543static void drmp3_L3_reorder(float *grbuf, float *scratch, const drmp3_uint8 *sfb)
1544{
1545 int i, len;
1546 float *src = grbuf, *dst = scratch;
1547
1548 for (;0 != (len = *sfb); sfb += 3, src += 2*len)
1549 {
1550 for (i = 0; i < len; i++, src++)
1551 {
1552 *dst++ = src[0*len];
1553 *dst++ = src[1*len];
1554 *dst++ = src[2*len];
1555 }
1556 }
1557 DRMP3_COPY_MEMORY(grbuf, scratch, (dst - scratch)*sizeof(float));
1558}
1559
1560static void drmp3_L3_antialias(float *grbuf, int nbands)
1561{
1562 static const float g_aa[2][8] = {
1563 {0.85749293f,0.88174200f,0.94962865f,0.98331459f,0.99551782f,0.99916056f,0.99989920f,0.99999316f},
1564 {0.51449576f,0.47173197f,0.31337745f,0.18191320f,0.09457419f,0.04096558f,0.01419856f,0.00369997f}
1565 };
1566
1567 for (; nbands > 0; nbands--, grbuf += 18)
1568 {
1569 int i = 0;
1570#if DRMP3_HAVE_SIMD
1571 if (drmp3_have_simd()) for (; i < 8; i += 4)
1572 {
1573 drmp3_f4 vu = DRMP3_VLD(grbuf + 18 + i);
1574 drmp3_f4 vd = DRMP3_VLD(grbuf + 14 - i);
1575 drmp3_f4 vc0 = DRMP3_VLD(g_aa[0] + i);
1576 drmp3_f4 vc1 = DRMP3_VLD(g_aa[1] + i);
1577 vd = DRMP3_VREV(vd);
1578 DRMP3_VSTORE(grbuf + 18 + i, DRMP3_VSUB(DRMP3_VMUL(vu, vc0), DRMP3_VMUL(vd, vc1)));
1579 vd = DRMP3_VADD(DRMP3_VMUL(vu, vc1), DRMP3_VMUL(vd, vc0));
1580 DRMP3_VSTORE(grbuf + 14 - i, DRMP3_VREV(vd));
1581 }
1582#endif
1583#ifndef DR_MP3_ONLY_SIMD
1584 for(; i < 8; i++)
1585 {
1586 float u = grbuf[18 + i];
1587 float d = grbuf[17 - i];
1588 grbuf[18 + i] = u*g_aa[0][i] - d*g_aa[1][i];
1589 grbuf[17 - i] = u*g_aa[1][i] + d*g_aa[0][i];
1590 }
1591#endif
1592 }
1593}
1594
1595static void drmp3_L3_dct3_9(float *y)
1596{
1597 float s0, s1, s2, s3, s4, s5, s6, s7, s8, t0, t2, t4;
1598
1599 s0 = y[0]; s2 = y[2]; s4 = y[4]; s6 = y[6]; s8 = y[8];
1600 t0 = s0 + s6*0.5f;
1601 s0 -= s6;
1602 t4 = (s4 + s2)*0.93969262f;
1603 t2 = (s8 + s2)*0.76604444f;
1604 s6 = (s4 - s8)*0.17364818f;
1605 s4 += s8 - s2;
1606
1607 s2 = s0 - s4*0.5f;
1608 y[4] = s4 + s0;
1609 s8 = t0 - t2 + s6;
1610 s0 = t0 - t4 + t2;
1611 s4 = t0 + t4 - s6;
1612
1613 s1 = y[1]; s3 = y[3]; s5 = y[5]; s7 = y[7];
1614
1615 s3 *= 0.86602540f;
1616 t0 = (s5 + s1)*0.98480775f;
1617 t4 = (s5 - s7)*0.34202014f;
1618 t2 = (s1 + s7)*0.64278761f;
1619 s1 = (s1 - s5 - s7)*0.86602540f;
1620
1621 s5 = t0 - s3 - t2;
1622 s7 = t4 - s3 - t0;
1623 s3 = t4 + s3 - t2;
1624
1625 y[0] = s4 - s7;
1626 y[1] = s2 + s1;
1627 y[2] = s0 - s3;
1628 y[3] = s8 + s5;
1629 y[5] = s8 - s5;
1630 y[6] = s0 + s3;
1631 y[7] = s2 - s1;
1632 y[8] = s4 + s7;
1633}
1634
1635static void drmp3_L3_imdct36(float *grbuf, float *overlap, const float *window, int nbands)
1636{
1637 int i, j;
1638 static const float g_twid9[18] = {
1639 0.73727734f,0.79335334f,0.84339145f,0.88701083f,0.92387953f,0.95371695f,0.97629601f,0.99144486f,0.99904822f,0.67559021f,0.60876143f,0.53729961f,0.46174861f,0.38268343f,0.30070580f,0.21643961f,0.13052619f,0.04361938f
1640 };
1641
1642 for (j = 0; j < nbands; j++, grbuf += 18, overlap += 9)
1643 {
1644 float co[9], si[9];
1645 co[0] = -grbuf[0];
1646 si[0] = grbuf[17];
1647 for (i = 0; i < 4; i++)
1648 {
1649 si[8 - 2*i] = grbuf[4*i + 1] - grbuf[4*i + 2];
1650 co[1 + 2*i] = grbuf[4*i + 1] + grbuf[4*i + 2];
1651 si[7 - 2*i] = grbuf[4*i + 4] - grbuf[4*i + 3];
1652 co[2 + 2*i] = -(grbuf[4*i + 3] + grbuf[4*i + 4]);
1653 }
1654 drmp3_L3_dct3_9(co);
1655 drmp3_L3_dct3_9(si);
1656
1657 si[1] = -si[1];
1658 si[3] = -si[3];
1659 si[5] = -si[5];
1660 si[7] = -si[7];
1661
1662 i = 0;
1663
1664#if DRMP3_HAVE_SIMD
1665 if (drmp3_have_simd()) for (; i < 8; i += 4)
1666 {
1667 drmp3_f4 vovl = DRMP3_VLD(overlap + i);
1668 drmp3_f4 vc = DRMP3_VLD(co + i);
1669 drmp3_f4 vs = DRMP3_VLD(si + i);
1670 drmp3_f4 vr0 = DRMP3_VLD(g_twid9 + i);
1671 drmp3_f4 vr1 = DRMP3_VLD(g_twid9 + 9 + i);
1672 drmp3_f4 vw0 = DRMP3_VLD(window + i);
1673 drmp3_f4 vw1 = DRMP3_VLD(window + 9 + i);
1674 drmp3_f4 vsum = DRMP3_VADD(DRMP3_VMUL(vc, vr1), DRMP3_VMUL(vs, vr0));
1675 DRMP3_VSTORE(overlap + i, DRMP3_VSUB(DRMP3_VMUL(vc, vr0), DRMP3_VMUL(vs, vr1)));
1676 DRMP3_VSTORE(grbuf + i, DRMP3_VSUB(DRMP3_VMUL(vovl, vw0), DRMP3_VMUL(vsum, vw1)));
1677 vsum = DRMP3_VADD(DRMP3_VMUL(vovl, vw1), DRMP3_VMUL(vsum, vw0));
1678 DRMP3_VSTORE(grbuf + 14 - i, DRMP3_VREV(vsum));
1679 }
1680#endif
1681 for (; i < 9; i++)
1682 {
1683 float ovl = overlap[i];
1684 float sum = co[i]*g_twid9[9 + i] + si[i]*g_twid9[0 + i];
1685 overlap[i] = co[i]*g_twid9[0 + i] - si[i]*g_twid9[9 + i];
1686 grbuf[i] = ovl*window[0 + i] - sum*window[9 + i];
1687 grbuf[17 - i] = ovl*window[9 + i] + sum*window[0 + i];
1688 }
1689 }
1690}
1691
1692static void drmp3_L3_idct3(float x0, float x1, float x2, float *dst)
1693{
1694 float m1 = x1*0.86602540f;
1695 float a1 = x0 - x2*0.5f;
1696 dst[1] = x0 + x2;
1697 dst[0] = a1 + m1;
1698 dst[2] = a1 - m1;
1699}
1700
1701static void drmp3_L3_imdct12(float *x, float *dst, float *overlap)
1702{
1703 static const float g_twid3[6] = { 0.79335334f,0.92387953f,0.99144486f, 0.60876143f,0.38268343f,0.13052619f };
1704 float co[3], si[3];
1705 int i;
1706
1707 drmp3_L3_idct3(-x[0], x[6] + x[3], x[12] + x[9], co);
1708 drmp3_L3_idct3(x[15], x[12] - x[9], x[6] - x[3], si);
1709 si[1] = -si[1];
1710
1711 for (i = 0; i < 3; i++)
1712 {
1713 float ovl = overlap[i];
1714 float sum = co[i]*g_twid3[3 + i] + si[i]*g_twid3[0 + i];
1715 overlap[i] = co[i]*g_twid3[0 + i] - si[i]*g_twid3[3 + i];
1716 dst[i] = ovl*g_twid3[2 - i] - sum*g_twid3[5 - i];
1717 dst[5 - i] = ovl*g_twid3[5 - i] + sum*g_twid3[2 - i];
1718 }
1719}
1720
1721static void drmp3_L3_imdct_short(float *grbuf, float *overlap, int nbands)
1722{
1723 for (;nbands > 0; nbands--, overlap += 9, grbuf += 18)
1724 {
1725 float tmp[18];
1726 DRMP3_COPY_MEMORY(tmp, grbuf, sizeof(tmp));
1727 DRMP3_COPY_MEMORY(grbuf, overlap, 6*sizeof(float));
1728 drmp3_L3_imdct12(tmp, grbuf + 6, overlap + 6);
1729 drmp3_L3_imdct12(tmp + 1, grbuf + 12, overlap + 6);
1730 drmp3_L3_imdct12(tmp + 2, overlap, overlap + 6);
1731 }
1732}
1733
1734static void drmp3_L3_change_sign(float *grbuf)
1735{
1736 int b, i;
1737 for (b = 0, grbuf += 18; b < 32; b += 2, grbuf += 36)
1738 for (i = 1; i < 18; i += 2)
1739 grbuf[i] = -grbuf[i];
1740}
1741
1742static void drmp3_L3_imdct_gr(float *grbuf, float *overlap, unsigned block_type, unsigned n_long_bands)
1743{
1744 static const float g_mdct_window[2][18] = {
1745 { 0.99904822f,0.99144486f,0.97629601f,0.95371695f,0.92387953f,0.88701083f,0.84339145f,0.79335334f,0.73727734f,0.04361938f,0.13052619f,0.21643961f,0.30070580f,0.38268343f,0.46174861f,0.53729961f,0.60876143f,0.67559021f },
1746 { 1,1,1,1,1,1,0.99144486f,0.92387953f,0.79335334f,0,0,0,0,0,0,0.13052619f,0.38268343f,0.60876143f }
1747 };
1748 if (n_long_bands)
1749 {
1750 drmp3_L3_imdct36(grbuf, overlap, g_mdct_window[0], n_long_bands);
1751 grbuf += 18*n_long_bands;
1752 overlap += 9*n_long_bands;
1753 }
1754 if (block_type == DRMP3_SHORT_BLOCK_TYPE)
1755 drmp3_L3_imdct_short(grbuf, overlap, 32 - n_long_bands);
1756 else
1757 drmp3_L3_imdct36(grbuf, overlap, g_mdct_window[block_type == DRMP3_STOP_BLOCK_TYPE], 32 - n_long_bands);
1758}
1759
1760static void drmp3_L3_save_reservoir(drmp3dec *h, drmp3dec_scratch *s)
1761{
1762 int pos = (s->bs.pos + 7)/8u;
1763 int remains = s->bs.limit/8u - pos;
1764 if (remains > DRMP3_MAX_BITRESERVOIR_BYTES)
1765 {
1766 pos += remains - DRMP3_MAX_BITRESERVOIR_BYTES;
1767 remains = DRMP3_MAX_BITRESERVOIR_BYTES;
1768 }
1769 if (remains > 0)
1770 {
1771 DRMP3_MOVE_MEMORY(h->reserv_buf, s->maindata + pos, remains);
1772 }
1773 h->reserv = remains;
1774}
1775
1776static int drmp3_L3_restore_reservoir(drmp3dec *h, drmp3_bs *bs, drmp3dec_scratch *s, int main_data_begin)
1777{
1778 int frame_bytes = (bs->limit - bs->pos)/8;
1779 int bytes_have = DRMP3_MIN(h->reserv, main_data_begin);
1780 DRMP3_COPY_MEMORY(s->maindata, h->reserv_buf + DRMP3_MAX(0, h->reserv - main_data_begin), DRMP3_MIN(h->reserv, main_data_begin));
1781 DRMP3_COPY_MEMORY(s->maindata + bytes_have, bs->buf + bs->pos/8, frame_bytes);
1782 drmp3_bs_init(&s->bs, s->maindata, bytes_have + frame_bytes);
1783 return h->reserv >= main_data_begin;
1784}
1785
1786static void drmp3_L3_decode(drmp3dec *h, drmp3dec_scratch *s, drmp3_L3_gr_info *gr_info, int nch)
1787{
1788 int ch;
1789
1790 for (ch = 0; ch < nch; ch++)
1791 {
1792 int layer3gr_limit = s->bs.pos + gr_info[ch].part_23_length;
1793 drmp3_L3_decode_scalefactors(h->header, s->ist_pos[ch], &s->bs, gr_info + ch, s->scf, ch);
1794 drmp3_L3_huffman(s->grbuf[ch], &s->bs, gr_info + ch, s->scf, layer3gr_limit);
1795 }
1796
1797 if (DRMP3_HDR_TEST_I_STEREO(h->header))
1798 {
1799 drmp3_L3_intensity_stereo(s->grbuf[0], s->ist_pos[1], gr_info, h->header);
1800 } else if (DRMP3_HDR_IS_MS_STEREO(h->header))
1801 {
1802 drmp3_L3_midside_stereo(s->grbuf[0], 576);
1803 }
1804
1805 for (ch = 0; ch < nch; ch++, gr_info++)
1806 {
1807 int aa_bands = 31;
1808 int n_long_bands = (gr_info->mixed_block_flag ? 2 : 0) << (int)(DRMP3_HDR_GET_MY_SAMPLE_RATE(h->header) == 2);
1809
1810 if (gr_info->n_short_sfb)
1811 {
1812 aa_bands = n_long_bands - 1;
1813 drmp3_L3_reorder(s->grbuf[ch] + n_long_bands*18, s->syn[0], gr_info->sfbtab + gr_info->n_long_sfb);
1814 }
1815
1816 drmp3_L3_antialias(s->grbuf[ch], aa_bands);
1817 drmp3_L3_imdct_gr(s->grbuf[ch], h->mdct_overlap[ch], gr_info->block_type, n_long_bands);
1818 drmp3_L3_change_sign(s->grbuf[ch]);
1819 }
1820}
1821
1822static void drmp3d_DCT_II(float *grbuf, int n)
1823{
1824 static const float g_sec[24] = {
1825 10.19000816f,0.50060302f,0.50241929f,3.40760851f,0.50547093f,0.52249861f,2.05778098f,0.51544732f,0.56694406f,1.48416460f,0.53104258f,0.64682180f,1.16943991f,0.55310392f,0.78815460f,0.97256821f,0.58293498f,1.06067765f,0.83934963f,0.62250412f,1.72244716f,0.74453628f,0.67480832f,5.10114861f
1826 };
1827 int i, k = 0;
1828#if DRMP3_HAVE_SIMD
1829 if (drmp3_have_simd()) for (; k < n; k += 4)
1830 {
1831 drmp3_f4 t[4][8], *x;
1832 float *y = grbuf + k;
1833
1834 for (x = t[0], i = 0; i < 8; i++, x++)
1835 {
1836 drmp3_f4 x0 = DRMP3_VLD(&y[i*18]);
1837 drmp3_f4 x1 = DRMP3_VLD(&y[(15 - i)*18]);
1838 drmp3_f4 x2 = DRMP3_VLD(&y[(16 + i)*18]);
1839 drmp3_f4 x3 = DRMP3_VLD(&y[(31 - i)*18]);
1840 drmp3_f4 t0 = DRMP3_VADD(x0, x3);
1841 drmp3_f4 t1 = DRMP3_VADD(x1, x2);
1842 drmp3_f4 t2 = DRMP3_VMUL_S(DRMP3_VSUB(x1, x2), g_sec[3*i + 0]);
1843 drmp3_f4 t3 = DRMP3_VMUL_S(DRMP3_VSUB(x0, x3), g_sec[3*i + 1]);
1844 x[0] = DRMP3_VADD(t0, t1);
1845 x[8] = DRMP3_VMUL_S(DRMP3_VSUB(t0, t1), g_sec[3*i + 2]);
1846 x[16] = DRMP3_VADD(t3, t2);
1847 x[24] = DRMP3_VMUL_S(DRMP3_VSUB(t3, t2), g_sec[3*i + 2]);
1848 }
1849 for (x = t[0], i = 0; i < 4; i++, x += 8)
1850 {
1851 drmp3_f4 x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4], x5 = x[5], x6 = x[6], x7 = x[7], xt;
1852 xt = DRMP3_VSUB(x0, x7); x0 = DRMP3_VADD(x0, x7);
1853 x7 = DRMP3_VSUB(x1, x6); x1 = DRMP3_VADD(x1, x6);
1854 x6 = DRMP3_VSUB(x2, x5); x2 = DRMP3_VADD(x2, x5);
1855 x5 = DRMP3_VSUB(x3, x4); x3 = DRMP3_VADD(x3, x4);
1856 x4 = DRMP3_VSUB(x0, x3); x0 = DRMP3_VADD(x0, x3);
1857 x3 = DRMP3_VSUB(x1, x2); x1 = DRMP3_VADD(x1, x2);
1858 x[0] = DRMP3_VADD(x0, x1);
1859 x[4] = DRMP3_VMUL_S(DRMP3_VSUB(x0, x1), 0.70710677f);
1860 x5 = DRMP3_VADD(x5, x6);
1861 x6 = DRMP3_VMUL_S(DRMP3_VADD(x6, x7), 0.70710677f);
1862 x7 = DRMP3_VADD(x7, xt);
1863 x3 = DRMP3_VMUL_S(DRMP3_VADD(x3, x4), 0.70710677f);
1864 x5 = DRMP3_VSUB(x5, DRMP3_VMUL_S(x7, 0.198912367f)); /* rotate by PI/8 */
1865 x7 = DRMP3_VADD(x7, DRMP3_VMUL_S(x5, 0.382683432f));
1866 x5 = DRMP3_VSUB(x5, DRMP3_VMUL_S(x7, 0.198912367f));
1867 x0 = DRMP3_VSUB(xt, x6); xt = DRMP3_VADD(xt, x6);
1868 x[1] = DRMP3_VMUL_S(DRMP3_VADD(xt, x7), 0.50979561f);
1869 x[2] = DRMP3_VMUL_S(DRMP3_VADD(x4, x3), 0.54119611f);
1870 x[3] = DRMP3_VMUL_S(DRMP3_VSUB(x0, x5), 0.60134488f);
1871 x[5] = DRMP3_VMUL_S(DRMP3_VADD(x0, x5), 0.89997619f);
1872 x[6] = DRMP3_VMUL_S(DRMP3_VSUB(x4, x3), 1.30656302f);
1873 x[7] = DRMP3_VMUL_S(DRMP3_VSUB(xt, x7), 2.56291556f);
1874 }
1875
1876 if (k > n - 3)
1877 {
1878#if DRMP3_HAVE_SSE
1879#define DRMP3_VSAVE2(i, v) _mm_storel_pi((__m64 *)(void*)&y[i*18], v)
1880#else
1881#define DRMP3_VSAVE2(i, v) vst1_f32((float32_t *)&y[(i)*18], vget_low_f32(v))
1882#endif
1883 for (i = 0; i < 7; i++, y += 4*18)
1884 {
1885 drmp3_f4 s = DRMP3_VADD(t[3][i], t[3][i + 1]);
1886 DRMP3_VSAVE2(0, t[0][i]);
1887 DRMP3_VSAVE2(1, DRMP3_VADD(t[2][i], s));
1888 DRMP3_VSAVE2(2, DRMP3_VADD(t[1][i], t[1][i + 1]));
1889 DRMP3_VSAVE2(3, DRMP3_VADD(t[2][1 + i], s));
1890 }
1891 DRMP3_VSAVE2(0, t[0][7]);
1892 DRMP3_VSAVE2(1, DRMP3_VADD(t[2][7], t[3][7]));
1893 DRMP3_VSAVE2(2, t[1][7]);
1894 DRMP3_VSAVE2(3, t[3][7]);
1895 } else
1896 {
1897#define DRMP3_VSAVE4(i, v) DRMP3_VSTORE(&y[(i)*18], v)
1898 for (i = 0; i < 7; i++, y += 4*18)
1899 {
1900 drmp3_f4 s = DRMP3_VADD(t[3][i], t[3][i + 1]);
1901 DRMP3_VSAVE4(0, t[0][i]);
1902 DRMP3_VSAVE4(1, DRMP3_VADD(t[2][i], s));
1903 DRMP3_VSAVE4(2, DRMP3_VADD(t[1][i], t[1][i + 1]));
1904 DRMP3_VSAVE4(3, DRMP3_VADD(t[2][1 + i], s));
1905 }
1906 DRMP3_VSAVE4(0, t[0][7]);
1907 DRMP3_VSAVE4(1, DRMP3_VADD(t[2][7], t[3][7]));
1908 DRMP3_VSAVE4(2, t[1][7]);
1909 DRMP3_VSAVE4(3, t[3][7]);
1910 }
1911 } else
1912#endif
1913#ifdef DR_MP3_ONLY_SIMD
1914 {} /* for HAVE_SIMD=1, MINIMP3_ONLY_SIMD=1 case we do not need non-intrinsic "else" branch */
1915#else
1916 for (; k < n; k++)
1917 {
1918 float t[4][8], *x, *y = grbuf + k;
1919
1920 for (x = t[0], i = 0; i < 8; i++, x++)
1921 {
1922 float x0 = y[i*18];
1923 float x1 = y[(15 - i)*18];
1924 float x2 = y[(16 + i)*18];
1925 float x3 = y[(31 - i)*18];
1926 float t0 = x0 + x3;
1927 float t1 = x1 + x2;
1928 float t2 = (x1 - x2)*g_sec[3*i + 0];
1929 float t3 = (x0 - x3)*g_sec[3*i + 1];
1930 x[0] = t0 + t1;
1931 x[8] = (t0 - t1)*g_sec[3*i + 2];
1932 x[16] = t3 + t2;
1933 x[24] = (t3 - t2)*g_sec[3*i + 2];
1934 }
1935 for (x = t[0], i = 0; i < 4; i++, x += 8)
1936 {
1937 float x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4], x5 = x[5], x6 = x[6], x7 = x[7], xt;
1938 xt = x0 - x7; x0 += x7;
1939 x7 = x1 - x6; x1 += x6;
1940 x6 = x2 - x5; x2 += x5;
1941 x5 = x3 - x4; x3 += x4;
1942 x4 = x0 - x3; x0 += x3;
1943 x3 = x1 - x2; x1 += x2;
1944 x[0] = x0 + x1;
1945 x[4] = (x0 - x1)*0.70710677f;
1946 x5 = x5 + x6;
1947 x6 = (x6 + x7)*0.70710677f;
1948 x7 = x7 + xt;
1949 x3 = (x3 + x4)*0.70710677f;
1950 x5 -= x7*0.198912367f; /* rotate by PI/8 */
1951 x7 += x5*0.382683432f;
1952 x5 -= x7*0.198912367f;
1953 x0 = xt - x6; xt += x6;
1954 x[1] = (xt + x7)*0.50979561f;
1955 x[2] = (x4 + x3)*0.54119611f;
1956 x[3] = (x0 - x5)*0.60134488f;
1957 x[5] = (x0 + x5)*0.89997619f;
1958 x[6] = (x4 - x3)*1.30656302f;
1959 x[7] = (xt - x7)*2.56291556f;
1960
1961 }
1962 for (i = 0; i < 7; i++, y += 4*18)
1963 {
1964 y[0*18] = t[0][i];
1965 y[1*18] = t[2][i] + t[3][i] + t[3][i + 1];
1966 y[2*18] = t[1][i] + t[1][i + 1];
1967 y[3*18] = t[2][i + 1] + t[3][i] + t[3][i + 1];
1968 }
1969 y[0*18] = t[0][7];
1970 y[1*18] = t[2][7] + t[3][7];
1971 y[2*18] = t[1][7];
1972 y[3*18] = t[3][7];
1973 }
1974#endif
1975}
1976
1977#ifndef DR_MP3_FLOAT_OUTPUT
1978typedef drmp3_int16 drmp3d_sample_t;
1979
1980static drmp3_int16 drmp3d_scale_pcm(float sample)
1981{
1982 drmp3_int16 s;
1983#if DRMP3_HAVE_ARMV6
1984 drmp3_int32 s32 = (drmp3_int32)(sample + .5f);
1985 s32 -= (s32 < 0);
1986 s = (drmp3_int16)drmp3_clip_int16_arm(s32);
1987#else
1988 if (sample >= 32766.5f) return (drmp3_int16) 32767;
1989 if (sample <= -32767.5f) return (drmp3_int16)-32768;
1990 s = (drmp3_int16)(sample + .5f);
1991 s -= (s < 0); /* away from zero, to be compliant */
1992#endif
1993 return s;
1994}
1995#else
1996typedef float drmp3d_sample_t;
1997
1998static float drmp3d_scale_pcm(float sample)
1999{
2000 return sample*(1.f/32768.f);
2001}
2002#endif
2003
2004static void drmp3d_synth_pair(drmp3d_sample_t *pcm, int nch, const float *z)
2005{
2006 float a;
2007 a = (z[14*64] - z[ 0]) * 29;
2008 a += (z[ 1*64] + z[13*64]) * 213;
2009 a += (z[12*64] - z[ 2*64]) * 459;
2010 a += (z[ 3*64] + z[11*64]) * 2037;
2011 a += (z[10*64] - z[ 4*64]) * 5153;
2012 a += (z[ 5*64] + z[ 9*64]) * 6574;
2013 a += (z[ 8*64] - z[ 6*64]) * 37489;
2014 a += z[ 7*64] * 75038;
2015 pcm[0] = drmp3d_scale_pcm(a);
2016
2017 z += 2;
2018 a = z[14*64] * 104;
2019 a += z[12*64] * 1567;
2020 a += z[10*64] * 9727;
2021 a += z[ 8*64] * 64019;
2022 a += z[ 6*64] * -9975;
2023 a += z[ 4*64] * -45;
2024 a += z[ 2*64] * 146;
2025 a += z[ 0*64] * -5;
2026 pcm[16*nch] = drmp3d_scale_pcm(a);
2027}
2028
2029static void drmp3d_synth(float *xl, drmp3d_sample_t *dstl, int nch, float *lins)
2030{
2031 int i;
2032 float *xr = xl + 576*(nch - 1);
2033 drmp3d_sample_t *dstr = dstl + (nch - 1);
2034
2035 static const float g_win[] = {
2036 -1,26,-31,208,218,401,-519,2063,2000,4788,-5517,7134,5959,35640,-39336,74992,
2037 -1,24,-35,202,222,347,-581,2080,1952,4425,-5879,7640,5288,33791,-41176,74856,
2038 -1,21,-38,196,225,294,-645,2087,1893,4063,-6237,8092,4561,31947,-43006,74630,
2039 -1,19,-41,190,227,244,-711,2085,1822,3705,-6589,8492,3776,30112,-44821,74313,
2040 -1,17,-45,183,228,197,-779,2075,1739,3351,-6935,8840,2935,28289,-46617,73908,
2041 -1,16,-49,176,228,153,-848,2057,1644,3004,-7271,9139,2037,26482,-48390,73415,
2042 -2,14,-53,169,227,111,-919,2032,1535,2663,-7597,9389,1082,24694,-50137,72835,
2043 -2,13,-58,161,224,72,-991,2001,1414,2330,-7910,9592,70,22929,-51853,72169,
2044 -2,11,-63,154,221,36,-1064,1962,1280,2006,-8209,9750,-998,21189,-53534,71420,
2045 -2,10,-68,147,215,2,-1137,1919,1131,1692,-8491,9863,-2122,19478,-55178,70590,
2046 -3,9,-73,139,208,-29,-1210,1870,970,1388,-8755,9935,-3300,17799,-56778,69679,
2047 -3,8,-79,132,200,-57,-1283,1817,794,1095,-8998,9966,-4533,16155,-58333,68692,
2048 -4,7,-85,125,189,-83,-1356,1759,605,814,-9219,9959,-5818,14548,-59838,67629,
2049 -4,7,-91,117,177,-106,-1428,1698,402,545,-9416,9916,-7154,12980,-61289,66494,
2050 -5,6,-97,111,163,-127,-1498,1634,185,288,-9585,9838,-8540,11455,-62684,65290
2051 };
2052 float *zlin = lins + 15*64;
2053 const float *w = g_win;
2054
2055 zlin[4*15] = xl[18*16];
2056 zlin[4*15 + 1] = xr[18*16];
2057 zlin[4*15 + 2] = xl[0];
2058 zlin[4*15 + 3] = xr[0];
2059
2060 zlin[4*31] = xl[1 + 18*16];
2061 zlin[4*31 + 1] = xr[1 + 18*16];
2062 zlin[4*31 + 2] = xl[1];
2063 zlin[4*31 + 3] = xr[1];
2064
2065 drmp3d_synth_pair(dstr, nch, lins + 4*15 + 1);
2066 drmp3d_synth_pair(dstr + 32*nch, nch, lins + 4*15 + 64 + 1);
2067 drmp3d_synth_pair(dstl, nch, lins + 4*15);
2068 drmp3d_synth_pair(dstl + 32*nch, nch, lins + 4*15 + 64);
2069
2070#if DRMP3_HAVE_SIMD
2071 if (drmp3_have_simd()) for (i = 14; i >= 0; i--)
2072 {
2073#define DRMP3_VLOAD(k) drmp3_f4 w0 = DRMP3_VSET(*w++); drmp3_f4 w1 = DRMP3_VSET(*w++); drmp3_f4 vz = DRMP3_VLD(&zlin[4*i - 64*k]); drmp3_f4 vy = DRMP3_VLD(&zlin[4*i - 64*(15 - k)]);
2074#define DRMP3_V0(k) { DRMP3_VLOAD(k) b = DRMP3_VADD(DRMP3_VMUL(vz, w1), DRMP3_VMUL(vy, w0)) ; a = DRMP3_VSUB(DRMP3_VMUL(vz, w0), DRMP3_VMUL(vy, w1)); }
2075#define DRMP3_V1(k) { DRMP3_VLOAD(k) b = DRMP3_VADD(b, DRMP3_VADD(DRMP3_VMUL(vz, w1), DRMP3_VMUL(vy, w0))); a = DRMP3_VADD(a, DRMP3_VSUB(DRMP3_VMUL(vz, w0), DRMP3_VMUL(vy, w1))); }
2076#define DRMP3_V2(k) { DRMP3_VLOAD(k) b = DRMP3_VADD(b, DRMP3_VADD(DRMP3_VMUL(vz, w1), DRMP3_VMUL(vy, w0))); a = DRMP3_VADD(a, DRMP3_VSUB(DRMP3_VMUL(vy, w1), DRMP3_VMUL(vz, w0))); }
2077 drmp3_f4 a, b;
2078 zlin[4*i] = xl[18*(31 - i)];
2079 zlin[4*i + 1] = xr[18*(31 - i)];
2080 zlin[4*i + 2] = xl[1 + 18*(31 - i)];
2081 zlin[4*i + 3] = xr[1 + 18*(31 - i)];
2082 zlin[4*i + 64] = xl[1 + 18*(1 + i)];
2083 zlin[4*i + 64 + 1] = xr[1 + 18*(1 + i)];
2084 zlin[4*i - 64 + 2] = xl[18*(1 + i)];
2085 zlin[4*i - 64 + 3] = xr[18*(1 + i)];
2086
2087 DRMP3_V0(0) DRMP3_V2(1) DRMP3_V1(2) DRMP3_V2(3) DRMP3_V1(4) DRMP3_V2(5) DRMP3_V1(6) DRMP3_V2(7)
2088
2089 {
2090#ifndef DR_MP3_FLOAT_OUTPUT
2091#if DRMP3_HAVE_SSE
2092 static const drmp3_f4 g_max = { 32767.0f, 32767.0f, 32767.0f, 32767.0f };
2093 static const drmp3_f4 g_min = { -32768.0f, -32768.0f, -32768.0f, -32768.0f };
2094 __m128i pcm8 = _mm_packs_epi32(_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(a, g_max), g_min)),
2095 _mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(b, g_max), g_min)));
2096 dstr[(15 - i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 1);
2097 dstr[(17 + i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 5);
2098 dstl[(15 - i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 0);
2099 dstl[(17 + i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 4);
2100 dstr[(47 - i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 3);
2101 dstr[(49 + i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 7);
2102 dstl[(47 - i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 2);
2103 dstl[(49 + i)*nch] = (drmp3_int16)_mm_extract_epi16(pcm8, 6);
2104#else
2105 int16x4_t pcma, pcmb;
2106 a = DRMP3_VADD(a, DRMP3_VSET(0.5f));
2107 b = DRMP3_VADD(b, DRMP3_VSET(0.5f));
2108 pcma = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(a), vreinterpretq_s32_u32(vcltq_f32(a, DRMP3_VSET(0)))));
2109 pcmb = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(b), vreinterpretq_s32_u32(vcltq_f32(b, DRMP3_VSET(0)))));
2110 vst1_lane_s16(dstr + (15 - i)*nch, pcma, 1);
2111 vst1_lane_s16(dstr + (17 + i)*nch, pcmb, 1);
2112 vst1_lane_s16(dstl + (15 - i)*nch, pcma, 0);
2113 vst1_lane_s16(dstl + (17 + i)*nch, pcmb, 0);
2114 vst1_lane_s16(dstr + (47 - i)*nch, pcma, 3);
2115 vst1_lane_s16(dstr + (49 + i)*nch, pcmb, 3);
2116 vst1_lane_s16(dstl + (47 - i)*nch, pcma, 2);
2117 vst1_lane_s16(dstl + (49 + i)*nch, pcmb, 2);
2118#endif
2119#else
2120 #if DRMP3_HAVE_SSE
2121 static const drmp3_f4 g_scale = { 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f };
2122 #else
2123 const drmp3_f4 g_scale = vdupq_n_f32(1.0f/32768.0f);
2124 #endif
2125 a = DRMP3_VMUL(a, g_scale);
2126 b = DRMP3_VMUL(b, g_scale);
2127#if DRMP3_HAVE_SSE
2128 _mm_store_ss(dstr + (15 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1)));
2129 _mm_store_ss(dstr + (17 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(1, 1, 1, 1)));
2130 _mm_store_ss(dstl + (15 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0)));
2131 _mm_store_ss(dstl + (17 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(0, 0, 0, 0)));
2132 _mm_store_ss(dstr + (47 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 3, 3, 3)));
2133 _mm_store_ss(dstr + (49 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 3, 3, 3)));
2134 _mm_store_ss(dstl + (47 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2)));
2135 _mm_store_ss(dstl + (49 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(2, 2, 2, 2)));
2136#else
2137 vst1q_lane_f32(dstr + (15 - i)*nch, a, 1);
2138 vst1q_lane_f32(dstr + (17 + i)*nch, b, 1);
2139 vst1q_lane_f32(dstl + (15 - i)*nch, a, 0);
2140 vst1q_lane_f32(dstl + (17 + i)*nch, b, 0);
2141 vst1q_lane_f32(dstr + (47 - i)*nch, a, 3);
2142 vst1q_lane_f32(dstr + (49 + i)*nch, b, 3);
2143 vst1q_lane_f32(dstl + (47 - i)*nch, a, 2);
2144 vst1q_lane_f32(dstl + (49 + i)*nch, b, 2);
2145#endif
2146#endif /* DR_MP3_FLOAT_OUTPUT */
2147 }
2148 } else
2149#endif
2150#ifdef DR_MP3_ONLY_SIMD
2151 {} /* for HAVE_SIMD=1, MINIMP3_ONLY_SIMD=1 case we do not need non-intrinsic "else" branch */
2152#else
2153 for (i = 14; i >= 0; i--)
2154 {
2155#define DRMP3_LOAD(k) float w0 = *w++; float w1 = *w++; float *vz = &zlin[4*i - k*64]; float *vy = &zlin[4*i - (15 - k)*64];
2156#define DRMP3_S0(k) { int j; DRMP3_LOAD(k); for (j = 0; j < 4; j++) b[j] = vz[j]*w1 + vy[j]*w0, a[j] = vz[j]*w0 - vy[j]*w1; }
2157#define DRMP3_S1(k) { int j; DRMP3_LOAD(k); for (j = 0; j < 4; j++) b[j] += vz[j]*w1 + vy[j]*w0, a[j] += vz[j]*w0 - vy[j]*w1; }
2158#define DRMP3_S2(k) { int j; DRMP3_LOAD(k); for (j = 0; j < 4; j++) b[j] += vz[j]*w1 + vy[j]*w0, a[j] += vy[j]*w1 - vz[j]*w0; }
2159 float a[4], b[4];
2160
2161 zlin[4*i] = xl[18*(31 - i)];
2162 zlin[4*i + 1] = xr[18*(31 - i)];
2163 zlin[4*i + 2] = xl[1 + 18*(31 - i)];
2164 zlin[4*i + 3] = xr[1 + 18*(31 - i)];
2165 zlin[4*(i + 16)] = xl[1 + 18*(1 + i)];
2166 zlin[4*(i + 16) + 1] = xr[1 + 18*(1 + i)];
2167 zlin[4*(i - 16) + 2] = xl[18*(1 + i)];
2168 zlin[4*(i - 16) + 3] = xr[18*(1 + i)];
2169
2170 DRMP3_S0(0) DRMP3_S2(1) DRMP3_S1(2) DRMP3_S2(3) DRMP3_S1(4) DRMP3_S2(5) DRMP3_S1(6) DRMP3_S2(7)
2171
2172 dstr[(15 - i)*nch] = drmp3d_scale_pcm(a[1]);
2173 dstr[(17 + i)*nch] = drmp3d_scale_pcm(b[1]);
2174 dstl[(15 - i)*nch] = drmp3d_scale_pcm(a[0]);
2175 dstl[(17 + i)*nch] = drmp3d_scale_pcm(b[0]);
2176 dstr[(47 - i)*nch] = drmp3d_scale_pcm(a[3]);
2177 dstr[(49 + i)*nch] = drmp3d_scale_pcm(b[3]);
2178 dstl[(47 - i)*nch] = drmp3d_scale_pcm(a[2]);
2179 dstl[(49 + i)*nch] = drmp3d_scale_pcm(b[2]);
2180 }
2181#endif
2182}
2183
2184static void drmp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, int nch, drmp3d_sample_t *pcm, float *lins)
2185{
2186 int i;
2187 for (i = 0; i < nch; i++)
2188 {
2189 drmp3d_DCT_II(grbuf + 576*i, nbands);
2190 }
2191
2192 DRMP3_COPY_MEMORY(lins, qmf_state, sizeof(float)*15*64);
2193
2194 for (i = 0; i < nbands; i += 2)
2195 {
2196 drmp3d_synth(grbuf + i, pcm + 32*nch*i, nch, lins + i*64);
2197 }
2198#ifndef DR_MP3_NONSTANDARD_BUT_LOGICAL
2199 if (nch == 1)
2200 {
2201 for (i = 0; i < 15*64; i += 2)
2202 {
2203 qmf_state[i] = lins[nbands*64 + i];
2204 }
2205 } else
2206#endif
2207 {
2208 DRMP3_COPY_MEMORY(qmf_state, lins + nbands*64, sizeof(float)*15*64);
2209 }
2210}
2211
2212static int drmp3d_match_frame(const drmp3_uint8 *hdr, int mp3_bytes, int frame_bytes)
2213{
2214 int i, nmatch;
2215 for (i = 0, nmatch = 0; nmatch < DRMP3_MAX_FRAME_SYNC_MATCHES; nmatch++)
2216 {
2217 i += drmp3_hdr_frame_bytes(hdr + i, frame_bytes) + drmp3_hdr_padding(hdr + i);
2218 if (i + DRMP3_HDR_SIZE > mp3_bytes)
2219 return nmatch > 0;
2220 if (!drmp3_hdr_compare(hdr, hdr + i))
2221 return 0;
2222 }
2223 return 1;
2224}
2225
2226static int drmp3d_find_frame(const drmp3_uint8 *mp3, int mp3_bytes, int *free_format_bytes, int *ptr_frame_bytes)
2227{
2228 int i, k;
2229 for (i = 0; i < mp3_bytes - DRMP3_HDR_SIZE; i++, mp3++)
2230 {
2231 if (drmp3_hdr_valid(mp3))
2232 {
2233 int frame_bytes = drmp3_hdr_frame_bytes(mp3, *free_format_bytes);
2234 int frame_and_padding = frame_bytes + drmp3_hdr_padding(mp3);
2235
2236 for (k = DRMP3_HDR_SIZE; !frame_bytes && k < DRMP3_MAX_FREE_FORMAT_FRAME_SIZE && i + 2*k < mp3_bytes - DRMP3_HDR_SIZE; k++)
2237 {
2238 if (drmp3_hdr_compare(mp3, mp3 + k))
2239 {
2240 int fb = k - drmp3_hdr_padding(mp3);
2241 int nextfb = fb + drmp3_hdr_padding(mp3 + k);
2242 if (i + k + nextfb + DRMP3_HDR_SIZE > mp3_bytes || !drmp3_hdr_compare(mp3, mp3 + k + nextfb))
2243 continue;
2244 frame_and_padding = k;
2245 frame_bytes = fb;
2246 *free_format_bytes = fb;
2247 }
2248 }
2249
2250 if ((frame_bytes && i + frame_and_padding <= mp3_bytes &&
2251 drmp3d_match_frame(mp3, mp3_bytes - i, frame_bytes)) ||
2252 (!i && frame_and_padding == mp3_bytes))
2253 {
2254 *ptr_frame_bytes = frame_and_padding;
2255 return i;
2256 }
2257 *free_format_bytes = 0;
2258 }
2259 }
2260 *ptr_frame_bytes = 0;
2261 return mp3_bytes;
2262}
2263
2264DRMP3_API void drmp3dec_init(drmp3dec *dec)
2265{
2266 dec->header[0] = 0;
2267}
2268
2269DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int mp3_bytes, void *pcm, drmp3dec_frame_info *info)
2270{
2271 int i = 0, igr, frame_size = 0, success = 1;
2272 const drmp3_uint8 *hdr;
2273 drmp3_bs bs_frame[1];
2274 drmp3dec_scratch scratch;
2275
2276 if (mp3_bytes > 4 && dec->header[0] == 0xff && drmp3_hdr_compare(dec->header, mp3))
2277 {
2278 frame_size = drmp3_hdr_frame_bytes(mp3, dec->free_format_bytes) + drmp3_hdr_padding(mp3);
2279 if (frame_size != mp3_bytes && (frame_size + DRMP3_HDR_SIZE > mp3_bytes || !drmp3_hdr_compare(mp3, mp3 + frame_size)))
2280 {
2281 frame_size = 0;
2282 }
2283 }
2284 if (!frame_size)
2285 {
2286 DRMP3_ZERO_MEMORY(dec, sizeof(drmp3dec));
2287 i = drmp3d_find_frame(mp3, mp3_bytes, &dec->free_format_bytes, &frame_size);
2288 if (!frame_size || i + frame_size > mp3_bytes)
2289 {
2290 info->frame_bytes = i;
2291 return 0;
2292 }
2293 }
2294
2295 hdr = mp3 + i;
2296 DRMP3_COPY_MEMORY(dec->header, hdr, DRMP3_HDR_SIZE);
2297 info->frame_bytes = i + frame_size;
2298 info->channels = DRMP3_HDR_IS_MONO(hdr) ? 1 : 2;
2299 info->hz = drmp3_hdr_sample_rate_hz(hdr);
2300 info->layer = 4 - DRMP3_HDR_GET_LAYER(hdr);
2301 info->bitrate_kbps = drmp3_hdr_bitrate_kbps(hdr);
2302
2303 drmp3_bs_init(bs_frame, hdr + DRMP3_HDR_SIZE, frame_size - DRMP3_HDR_SIZE);
2304 if (DRMP3_HDR_IS_CRC(hdr))
2305 {
2306 drmp3_bs_get_bits(bs_frame, 16);
2307 }
2308
2309 if (info->layer == 3)
2310 {
2311 int main_data_begin = drmp3_L3_read_side_info(bs_frame, scratch.gr_info, hdr);
2312 if (main_data_begin < 0 || bs_frame->pos > bs_frame->limit)
2313 {
2314 drmp3dec_init(dec);
2315 return 0;
2316 }
2317 success = drmp3_L3_restore_reservoir(dec, bs_frame, &scratch, main_data_begin);
2318 if (success && pcm != NULL)
2319 {
2320 for (igr = 0; igr < (DRMP3_HDR_TEST_MPEG1(hdr) ? 2 : 1); igr++, pcm = DRMP3_OFFSET_PTR(pcm, sizeof(drmp3d_sample_t)*576*info->channels))
2321 {
2322 DRMP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float));
2323 drmp3_L3_decode(dec, &scratch, scratch.gr_info + igr*info->channels, info->channels);
2324 drmp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 18, info->channels, (drmp3d_sample_t*)pcm, scratch.syn[0]);
2325 }
2326 }
2327 drmp3_L3_save_reservoir(dec, &scratch);
2328 } else
2329 {
2330#ifdef DR_MP3_ONLY_MP3
2331 return 0;
2332#else
2333 drmp3_L12_scale_info sci[1];
2334
2335 if (pcm == NULL) {
2336 return drmp3_hdr_frame_samples(hdr);
2337 }
2338
2339 drmp3_L12_read_scale_info(hdr, bs_frame, sci);
2340
2341 DRMP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float));
2342 for (i = 0, igr = 0; igr < 3; igr++)
2343 {
2344 if (12 == (i += drmp3_L12_dequantize_granule(scratch.grbuf[0] + i, bs_frame, sci, info->layer | 1)))
2345 {
2346 i = 0;
2347 drmp3_L12_apply_scf_384(sci, sci->scf + igr, scratch.grbuf[0]);
2348 drmp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 12, info->channels, (drmp3d_sample_t*)pcm, scratch.syn[0]);
2349 DRMP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float));
2350 pcm = DRMP3_OFFSET_PTR(pcm, sizeof(drmp3d_sample_t)*384*info->channels);
2351 }
2352 if (bs_frame->pos > bs_frame->limit)
2353 {
2354 drmp3dec_init(dec);
2355 return 0;
2356 }
2357 }
2358#endif
2359 }
2360
2361 return success*drmp3_hdr_frame_samples(dec->header);
2362}
2363
2364DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num_samples)
2365{
2366 size_t i = 0;
2367#if DRMP3_HAVE_SIMD
2368 size_t aligned_count = num_samples & ~7;
2369 for(; i < aligned_count; i+=8)
2370 {
2371 drmp3_f4 scale = DRMP3_VSET(32768.0f);
2372 drmp3_f4 a = DRMP3_VMUL(DRMP3_VLD(&in[i ]), scale);
2373 drmp3_f4 b = DRMP3_VMUL(DRMP3_VLD(&in[i+4]), scale);
2374#if DRMP3_HAVE_SSE
2375 drmp3_f4 s16max = DRMP3_VSET( 32767.0f);
2376 drmp3_f4 s16min = DRMP3_VSET(-32768.0f);
2377 __m128i pcm8 = _mm_packs_epi32(_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(a, s16max), s16min)),
2378 _mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(b, s16max), s16min)));
2379 out[i ] = (drmp3_int16)_mm_extract_epi16(pcm8, 0);
2380 out[i+1] = (drmp3_int16)_mm_extract_epi16(pcm8, 1);
2381 out[i+2] = (drmp3_int16)_mm_extract_epi16(pcm8, 2);
2382 out[i+3] = (drmp3_int16)_mm_extract_epi16(pcm8, 3);
2383 out[i+4] = (drmp3_int16)_mm_extract_epi16(pcm8, 4);
2384 out[i+5] = (drmp3_int16)_mm_extract_epi16(pcm8, 5);
2385 out[i+6] = (drmp3_int16)_mm_extract_epi16(pcm8, 6);
2386 out[i+7] = (drmp3_int16)_mm_extract_epi16(pcm8, 7);
2387#else
2388 int16x4_t pcma, pcmb;
2389 a = DRMP3_VADD(a, DRMP3_VSET(0.5f));
2390 b = DRMP3_VADD(b, DRMP3_VSET(0.5f));
2391 pcma = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(a), vreinterpretq_s32_u32(vcltq_f32(a, DRMP3_VSET(0)))));
2392 pcmb = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(b), vreinterpretq_s32_u32(vcltq_f32(b, DRMP3_VSET(0)))));
2393 vst1_lane_s16(out+i , pcma, 0);
2394 vst1_lane_s16(out+i+1, pcma, 1);
2395 vst1_lane_s16(out+i+2, pcma, 2);
2396 vst1_lane_s16(out+i+3, pcma, 3);
2397 vst1_lane_s16(out+i+4, pcmb, 0);
2398 vst1_lane_s16(out+i+5, pcmb, 1);
2399 vst1_lane_s16(out+i+6, pcmb, 2);
2400 vst1_lane_s16(out+i+7, pcmb, 3);
2401#endif
2402 }
2403#endif
2404 for(; i < num_samples; i++)
2405 {
2406 float sample = in[i] * 32768.0f;
2407 if (sample >= 32766.5f)
2408 out[i] = (drmp3_int16) 32767;
2409 else if (sample <= -32767.5f)
2410 out[i] = (drmp3_int16)-32768;
2411 else
2412 {
2413 short s = (drmp3_int16)(sample + .5f);
2414 s -= (s < 0); /* away from zero, to be compliant */
2415 out[i] = s;
2416 }
2417 }
2418}
2419
2420
2421
2422/************************************************************************************************************************************************************
2423
2424 Main Public API
2425
2426 ************************************************************************************************************************************************************/
2427/* SIZE_MAX */
2428#if defined(SIZE_MAX)
2429 #define DRMP3_SIZE_MAX SIZE_MAX
2430#else
2431 #if defined(_WIN64) || defined(_LP64) || defined(__LP64__)
2432 #define DRMP3_SIZE_MAX ((drmp3_uint64)0xFFFFFFFFFFFFFFFF)
2433 #else
2434 #define DRMP3_SIZE_MAX 0xFFFFFFFF
2435 #endif
2436#endif
2437/* End SIZE_MAX */
2438
2439/* Options. */
2440#ifndef DRMP3_SEEK_LEADING_MP3_FRAMES
2441#define DRMP3_SEEK_LEADING_MP3_FRAMES 2
2442#endif
2443
2444#define DRMP3_MIN_DATA_CHUNK_SIZE 16384
2445
2446/* The size in bytes of each chunk of data to read from the MP3 stream. minimp3 recommends at least 16K, but in an attempt to reduce data movement I'm making this slightly larger. */
2447#ifndef DRMP3_DATA_CHUNK_SIZE
2448#define DRMP3_DATA_CHUNK_SIZE (DRMP3_MIN_DATA_CHUNK_SIZE*4)
2449#endif
2450
2451
2452#define DRMP3_COUNTOF(x) (sizeof(x) / sizeof(x[0]))
2453#define DRMP3_CLAMP(x, lo, hi) (DRMP3_MAX(lo, DRMP3_MIN(x, hi)))
2454
2455#ifndef DRMP3_PI_D
2456#define DRMP3_PI_D 3.14159265358979323846264
2457#endif
2458
2459#define DRMP3_DEFAULT_RESAMPLER_LPF_ORDER 2
2460
2461static DRMP3_INLINE float drmp3_mix_f32(float x, float y, float a)
2462{
2463 return x*(1-a) + y*a;
2464}
2465static DRMP3_INLINE float drmp3_mix_f32_fast(float x, float y, float a)
2466{
2467 float r0 = (y - x);
2468 float r1 = r0*a;
2469 return x + r1;
2470 /*return x + (y - x)*a;*/
2471}
2472
2473
2474/*
2475Greatest common factor using Euclid's algorithm iteratively.
2476*/
2477static DRMP3_INLINE drmp3_uint32 drmp3_gcf_u32(drmp3_uint32 a, drmp3_uint32 b)
2478{
2479 for (;;) {
2480 if (b == 0) {
2481 break;
2482 } else {
2483 drmp3_uint32 t = a;
2484 a = b;
2485 b = t % a;
2486 }
2487 }
2488
2489 return a;
2490}
2491
2492
2493static void* drmp3__malloc_default(size_t sz, void* pUserData)
2494{
2495 (void)pUserData;
2496 return DRMP3_MALLOC(sz);
2497}
2498
2499static void* drmp3__realloc_default(void* p, size_t sz, void* pUserData)
2500{
2501 (void)pUserData;
2502 return DRMP3_REALLOC(p, sz);
2503}
2504
2505static void drmp3__free_default(void* p, void* pUserData)
2506{
2507 (void)pUserData;
2508 DRMP3_FREE(p);
2509}
2510
2511
2512static void* drmp3__malloc_from_callbacks(size_t sz, const drmp3_allocation_callbacks* pAllocationCallbacks)
2513{
2514 if (pAllocationCallbacks == NULL) {
2515 return NULL;
2516 }
2517
2518 if (pAllocationCallbacks->onMalloc != NULL) {
2519 return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData);
2520 }
2521
2522 /* Try using realloc(). */
2523 if (pAllocationCallbacks->onRealloc != NULL) {
2524 return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData);
2525 }
2526
2527 return NULL;
2528}
2529
2530static void* drmp3__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drmp3_allocation_callbacks* pAllocationCallbacks)
2531{
2532 if (pAllocationCallbacks == NULL) {
2533 return NULL;
2534 }
2535
2536 if (pAllocationCallbacks->onRealloc != NULL) {
2537 return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData);
2538 }
2539
2540 /* Try emulating realloc() in terms of malloc()/free(). */
2541 if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) {
2542 void* p2;
2543
2544 p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData);
2545 if (p2 == NULL) {
2546 return NULL;
2547 }
2548
2549 if (p != NULL) {
2550 DRMP3_COPY_MEMORY(p2, p, szOld);
2551 pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
2552 }
2553
2554 return p2;
2555 }
2556
2557 return NULL;
2558}
2559
2560static void drmp3__free_from_callbacks(void* p, const drmp3_allocation_callbacks* pAllocationCallbacks)
2561{
2562 if (p == NULL || pAllocationCallbacks == NULL) {
2563 return;
2564 }
2565
2566 if (pAllocationCallbacks->onFree != NULL) {
2567 pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
2568 }
2569}
2570
2571
2572static drmp3_allocation_callbacks drmp3_copy_allocation_callbacks_or_defaults(const drmp3_allocation_callbacks* pAllocationCallbacks)
2573{
2574 if (pAllocationCallbacks != NULL) {
2575 /* Copy. */
2576 return *pAllocationCallbacks;
2577 } else {
2578 /* Defaults. */
2579 drmp3_allocation_callbacks allocationCallbacks;
2580 allocationCallbacks.pUserData = NULL;
2581 allocationCallbacks.onMalloc = drmp3__malloc_default;
2582 allocationCallbacks.onRealloc = drmp3__realloc_default;
2583 allocationCallbacks.onFree = drmp3__free_default;
2584 return allocationCallbacks;
2585 }
2586}
2587
2588
2589
2590static size_t drmp3__on_read(drmp3* pMP3, void* pBufferOut, size_t bytesToRead)
2591{
2592 size_t bytesRead = pMP3->onRead(pMP3->pUserData, pBufferOut, bytesToRead);
2593 pMP3->streamCursor += bytesRead;
2594 return bytesRead;
2595}
2596
2597static drmp3_bool32 drmp3__on_seek(drmp3* pMP3, int offset, drmp3_seek_origin origin)
2598{
2599 DRMP3_ASSERT(offset >= 0);
2600
2601 if (!pMP3->onSeek(pMP3->pUserData, offset, origin)) {
2602 return DRMP3_FALSE;
2603 }
2604
2605 if (origin == drmp3_seek_origin_start) {
2606 pMP3->streamCursor = (drmp3_uint64)offset;
2607 } else {
2608 pMP3->streamCursor += offset;
2609 }
2610
2611 return DRMP3_TRUE;
2612}
2613
2614static drmp3_bool32 drmp3__on_seek_64(drmp3* pMP3, drmp3_uint64 offset, drmp3_seek_origin origin)
2615{
2616 if (offset <= 0x7FFFFFFF) {
2617 return drmp3__on_seek(pMP3, (int)offset, origin);
2618 }
2619
2620
2621 /* Getting here "offset" is too large for a 32-bit integer. We just keep seeking forward until we hit the offset. */
2622 if (!drmp3__on_seek(pMP3, 0x7FFFFFFF, drmp3_seek_origin_start)) {
2623 return DRMP3_FALSE;
2624 }
2625
2626 offset -= 0x7FFFFFFF;
2627 while (offset > 0) {
2628 if (offset <= 0x7FFFFFFF) {
2629 if (!drmp3__on_seek(pMP3, (int)offset, drmp3_seek_origin_current)) {
2630 return DRMP3_FALSE;
2631 }
2632 offset = 0;
2633 } else {
2634 if (!drmp3__on_seek(pMP3, 0x7FFFFFFF, drmp3_seek_origin_current)) {
2635 return DRMP3_FALSE;
2636 }
2637 offset -= 0x7FFFFFFF;
2638 }
2639 }
2640
2641 return DRMP3_TRUE;
2642}
2643
2644
2645static drmp3_uint32 drmp3_decode_next_frame_ex__callbacks(drmp3* pMP3, drmp3d_sample_t* pPCMFrames)
2646{
2647 drmp3_uint32 pcmFramesRead = 0;
2648
2649 DRMP3_ASSERT(pMP3 != NULL);
2650 DRMP3_ASSERT(pMP3->onRead != NULL);
2651
2652 if (pMP3->atEnd) {
2653 return 0;
2654 }
2655
2656 for (;;) {
2657 drmp3dec_frame_info info;
2658
2659 /* minimp3 recommends doing data submission in chunks of at least 16K. If we don't have at least 16K bytes available, get more. */
2660 if (pMP3->dataSize < DRMP3_MIN_DATA_CHUNK_SIZE) {
2661 size_t bytesRead;
2662
2663 /* First we need to move the data down. */
2664 if (pMP3->pData != NULL) {
2665 DRMP3_MOVE_MEMORY(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize);
2666 }
2667
2668 pMP3->dataConsumed = 0;
2669
2670 if (pMP3->dataCapacity < DRMP3_DATA_CHUNK_SIZE) {
2671 drmp3_uint8* pNewData;
2672 size_t newDataCap;
2673
2674 newDataCap = DRMP3_DATA_CHUNK_SIZE;
2675
2676 pNewData = (drmp3_uint8*)drmp3__realloc_from_callbacks(pMP3->pData, newDataCap, pMP3->dataCapacity, &pMP3->allocationCallbacks);
2677 if (pNewData == NULL) {
2678 return 0; /* Out of memory. */
2679 }
2680
2681 pMP3->pData = pNewData;
2682 pMP3->dataCapacity = newDataCap;
2683 }
2684
2685 bytesRead = drmp3__on_read(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize));
2686 if (bytesRead == 0) {
2687 if (pMP3->dataSize == 0) {
2688 pMP3->atEnd = DRMP3_TRUE;
2689 return 0; /* No data. */
2690 }
2691 }
2692
2693 pMP3->dataSize += bytesRead;
2694 }
2695
2696 if (pMP3->dataSize > INT_MAX) {
2697 pMP3->atEnd = DRMP3_TRUE;
2698 return 0; /* File too big. */
2699 }
2700
2701 DRMP3_ASSERT(pMP3->pData != NULL);
2702 DRMP3_ASSERT(pMP3->dataCapacity > 0);
2703
2704 /* Do a runtime check here to try silencing a false-positive from clang-analyzer. */
2705 if (pMP3->pData == NULL) {
2706 return 0;
2707 }
2708
2709 pcmFramesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->pData + pMP3->dataConsumed, (int)pMP3->dataSize, pPCMFrames, &info); /* <-- Safe size_t -> int conversion thanks to the check above. */
2710
2711 /* Consume the data. */
2712 if (info.frame_bytes > 0) {
2713 pMP3->dataConsumed += (size_t)info.frame_bytes;
2714 pMP3->dataSize -= (size_t)info.frame_bytes;
2715 }
2716
2717 /* pcmFramesRead will be equal to 0 if decoding failed. If it is zero and info.frame_bytes > 0 then we have successfully decoded the frame. */
2718 if (pcmFramesRead > 0) {
2719 pcmFramesRead = drmp3_hdr_frame_samples(pMP3->decoder.header);
2720 pMP3->pcmFramesConsumedInMP3Frame = 0;
2721 pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead;
2722 pMP3->mp3FrameChannels = info.channels;
2723 pMP3->mp3FrameSampleRate = info.hz;
2724 break;
2725 } else if (info.frame_bytes == 0) {
2726 /* Need more data. minimp3 recommends doing data submission in 16K chunks. */
2727 size_t bytesRead;
2728
2729 /* First we need to move the data down. */
2730 DRMP3_MOVE_MEMORY(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize);
2731 pMP3->dataConsumed = 0;
2732
2733 if (pMP3->dataCapacity == pMP3->dataSize) {
2734 /* No room. Expand. */
2735 drmp3_uint8* pNewData;
2736 size_t newDataCap;
2737
2738 newDataCap = pMP3->dataCapacity + DRMP3_DATA_CHUNK_SIZE;
2739
2740 pNewData = (drmp3_uint8*)drmp3__realloc_from_callbacks(pMP3->pData, newDataCap, pMP3->dataCapacity, &pMP3->allocationCallbacks);
2741 if (pNewData == NULL) {
2742 return 0; /* Out of memory. */
2743 }
2744
2745 pMP3->pData = pNewData;
2746 pMP3->dataCapacity = newDataCap;
2747 }
2748
2749 /* Fill in a chunk. */
2750 bytesRead = drmp3__on_read(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize));
2751 if (bytesRead == 0) {
2752 pMP3->atEnd = DRMP3_TRUE;
2753 return 0; /* Error reading more data. */
2754 }
2755
2756 pMP3->dataSize += bytesRead;
2757 }
2758 };
2759
2760 return pcmFramesRead;
2761}
2762
2763static drmp3_uint32 drmp3_decode_next_frame_ex__memory(drmp3* pMP3, drmp3d_sample_t* pPCMFrames)
2764{
2765 drmp3_uint32 pcmFramesRead = 0;
2766 drmp3dec_frame_info info;
2767
2768 DRMP3_ASSERT(pMP3 != NULL);
2769 DRMP3_ASSERT(pMP3->memory.pData != NULL);
2770
2771 if (pMP3->atEnd) {
2772 return 0;
2773 }
2774
2775 for (;;) {
2776 pcmFramesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->memory.pData + pMP3->memory.currentReadPos, (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos), pPCMFrames, &info);
2777 if (pcmFramesRead > 0) {
2778 pcmFramesRead = drmp3_hdr_frame_samples(pMP3->decoder.header);
2779 pMP3->pcmFramesConsumedInMP3Frame = 0;
2780 pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead;
2781 pMP3->mp3FrameChannels = info.channels;
2782 pMP3->mp3FrameSampleRate = info.hz;
2783 break;
2784 } else if (info.frame_bytes > 0) {
2785 /* No frames were read, but it looks like we skipped past one. Read the next MP3 frame. */
2786 pMP3->memory.currentReadPos += (size_t)info.frame_bytes;
2787 } else {
2788 /* Nothing at all was read. Abort. */
2789 break;
2790 }
2791 }
2792
2793 /* Consume the data. */
2794 pMP3->memory.currentReadPos += (size_t)info.frame_bytes;
2795
2796 return pcmFramesRead;
2797}
2798
2799static drmp3_uint32 drmp3_decode_next_frame_ex(drmp3* pMP3, drmp3d_sample_t* pPCMFrames)
2800{
2801 if (pMP3->memory.pData != NULL && pMP3->memory.dataSize > 0) {
2802 return drmp3_decode_next_frame_ex__memory(pMP3, pPCMFrames);
2803 } else {
2804 return drmp3_decode_next_frame_ex__callbacks(pMP3, pPCMFrames);
2805 }
2806}
2807
2808static drmp3_uint32 drmp3_decode_next_frame(drmp3* pMP3)
2809{
2810 DRMP3_ASSERT(pMP3 != NULL);
2811 return drmp3_decode_next_frame_ex(pMP3, (drmp3d_sample_t*)pMP3->pcmFrames);
2812}
2813
2814#if 0
2815static drmp3_uint32 drmp3_seek_next_frame(drmp3* pMP3)
2816{
2817 drmp3_uint32 pcmFrameCount;
2818
2819 DRMP3_ASSERT(pMP3 != NULL);
2820
2821 pcmFrameCount = drmp3_decode_next_frame_ex(pMP3, NULL);
2822 if (pcmFrameCount == 0) {
2823 return 0;
2824 }
2825
2826 /* We have essentially just skipped past the frame, so just set the remaining samples to 0. */
2827 pMP3->currentPCMFrame += pcmFrameCount;
2828 pMP3->pcmFramesConsumedInMP3Frame = pcmFrameCount;
2829 pMP3->pcmFramesRemainingInMP3Frame = 0;
2830
2831 return pcmFrameCount;
2832}
2833#endif
2834
2835static drmp3_bool32 drmp3_init_internal(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, const drmp3_allocation_callbacks* pAllocationCallbacks)
2836{
2837 DRMP3_ASSERT(pMP3 != NULL);
2838 DRMP3_ASSERT(onRead != NULL);
2839
2840 /* This function assumes the output object has already been reset to 0. Do not do that here, otherwise things will break. */
2841 drmp3dec_init(&pMP3->decoder);
2842
2843 pMP3->onRead = onRead;
2844 pMP3->onSeek = onSeek;
2845 pMP3->pUserData = pUserData;
2846 pMP3->allocationCallbacks = drmp3_copy_allocation_callbacks_or_defaults(pAllocationCallbacks);
2847
2848 if (pMP3->allocationCallbacks.onFree == NULL || (pMP3->allocationCallbacks.onMalloc == NULL && pMP3->allocationCallbacks.onRealloc == NULL)) {
2849 return DRMP3_FALSE; /* Invalid allocation callbacks. */
2850 }
2851
2852 /* Decode the first frame to confirm that it is indeed a valid MP3 stream. */
2853 if (drmp3_decode_next_frame(pMP3) == 0) {
2854 drmp3__free_from_callbacks(pMP3->pData, &pMP3->allocationCallbacks); /* The call above may have allocated memory. Need to make sure it's freed before aborting. */
2855 return DRMP3_FALSE; /* Not a valid MP3 stream. */
2856 }
2857
2858 pMP3->channels = pMP3->mp3FrameChannels;
2859 pMP3->sampleRate = pMP3->mp3FrameSampleRate;
2860
2861 return DRMP3_TRUE;
2862}
2863
2864DRMP3_API drmp3_bool32 drmp3_init(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, const drmp3_allocation_callbacks* pAllocationCallbacks)
2865{
2866 if (pMP3 == NULL || onRead == NULL) {
2867 return DRMP3_FALSE;
2868 }
2869
2870 DRMP3_ZERO_OBJECT(pMP3);
2871 return drmp3_init_internal(pMP3, onRead, onSeek, pUserData, pAllocationCallbacks);
2872}
2873
2874
2875static size_t drmp3__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead)
2876{
2877 drmp3* pMP3 = (drmp3*)pUserData;
2878 size_t bytesRemaining;
2879
2880 DRMP3_ASSERT(pMP3 != NULL);
2881 DRMP3_ASSERT(pMP3->memory.dataSize >= pMP3->memory.currentReadPos);
2882
2883 bytesRemaining = pMP3->memory.dataSize - pMP3->memory.currentReadPos;
2884 if (bytesToRead > bytesRemaining) {
2885 bytesToRead = bytesRemaining;
2886 }
2887
2888 if (bytesToRead > 0) {
2889 DRMP3_COPY_MEMORY(pBufferOut, pMP3->memory.pData + pMP3->memory.currentReadPos, bytesToRead);
2890 pMP3->memory.currentReadPos += bytesToRead;
2891 }
2892
2893 return bytesToRead;
2894}
2895
2896static drmp3_bool32 drmp3__on_seek_memory(void* pUserData, int byteOffset, drmp3_seek_origin origin)
2897{
2898 drmp3* pMP3 = (drmp3*)pUserData;
2899
2900 DRMP3_ASSERT(pMP3 != NULL);
2901
2902 if (origin == drmp3_seek_origin_current) {
2903 if (byteOffset > 0) {
2904 if (pMP3->memory.currentReadPos + byteOffset > pMP3->memory.dataSize) {
2905 byteOffset = (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos); /* Trying to seek too far forward. */
2906 }
2907 } else {
2908 if (pMP3->memory.currentReadPos < (size_t)-byteOffset) {
2909 byteOffset = -(int)pMP3->memory.currentReadPos; /* Trying to seek too far backwards. */
2910 }
2911 }
2912
2913 /* This will never underflow thanks to the clamps above. */
2914 pMP3->memory.currentReadPos += byteOffset;
2915 } else {
2916 if ((drmp3_uint32)byteOffset <= pMP3->memory.dataSize) {
2917 pMP3->memory.currentReadPos = byteOffset;
2918 } else {
2919 pMP3->memory.currentReadPos = pMP3->memory.dataSize; /* Trying to seek too far forward. */
2920 }
2921 }
2922
2923 return DRMP3_TRUE;
2924}
2925
2926DRMP3_API drmp3_bool32 drmp3_init_memory(drmp3* pMP3, const void* pData, size_t dataSize, const drmp3_allocation_callbacks* pAllocationCallbacks)
2927{
2928 if (pMP3 == NULL) {
2929 return DRMP3_FALSE;
2930 }
2931
2932 DRMP3_ZERO_OBJECT(pMP3);
2933
2934 if (pData == NULL || dataSize == 0) {
2935 return DRMP3_FALSE;
2936 }
2937
2938 pMP3->memory.pData = (const drmp3_uint8*)pData;
2939 pMP3->memory.dataSize = dataSize;
2940 pMP3->memory.currentReadPos = 0;
2941
2942 return drmp3_init_internal(pMP3, drmp3__on_read_memory, drmp3__on_seek_memory, pMP3, pAllocationCallbacks);
2943}
2944
2945
2946#ifndef DR_MP3_NO_STDIO
2947#include <stdio.h>
2948#include <wchar.h> /* For wcslen(), wcsrtombs() */
2949
2950/* Errno */
2951/* drmp3_result_from_errno() is only used inside DR_MP3_NO_STDIO for now. Move this out if it's ever used elsewhere. */
2952#include <errno.h>
2953static drmp3_result drmp3_result_from_errno(int e)
2954{
2955 switch (e)
2956 {
2957 case 0: return DRMP3_SUCCESS;
2958 #ifdef EPERM
2959 case EPERM: return DRMP3_INVALID_OPERATION;
2960 #endif
2961 #ifdef ENOENT
2962 case ENOENT: return DRMP3_DOES_NOT_EXIST;
2963 #endif
2964 #ifdef ESRCH
2965 case ESRCH: return DRMP3_DOES_NOT_EXIST;
2966 #endif
2967 #ifdef EINTR
2968 case EINTR: return DRMP3_INTERRUPT;
2969 #endif
2970 #ifdef EIO
2971 case EIO: return DRMP3_IO_ERROR;
2972 #endif
2973 #ifdef ENXIO
2974 case ENXIO: return DRMP3_DOES_NOT_EXIST;
2975 #endif
2976 #ifdef E2BIG
2977 case E2BIG: return DRMP3_INVALID_ARGS;
2978 #endif
2979 #ifdef ENOEXEC
2980 case ENOEXEC: return DRMP3_INVALID_FILE;
2981 #endif
2982 #ifdef EBADF
2983 case EBADF: return DRMP3_INVALID_FILE;
2984 #endif
2985 #ifdef ECHILD
2986 case ECHILD: return DRMP3_ERROR;
2987 #endif
2988 #ifdef EAGAIN
2989 case EAGAIN: return DRMP3_UNAVAILABLE;
2990 #endif
2991 #ifdef ENOMEM
2992 case ENOMEM: return DRMP3_OUT_OF_MEMORY;
2993 #endif
2994 #ifdef EACCES
2995 case EACCES: return DRMP3_ACCESS_DENIED;
2996 #endif
2997 #ifdef EFAULT
2998 case EFAULT: return DRMP3_BAD_ADDRESS;
2999 #endif
3000 #ifdef ENOTBLK
3001 case ENOTBLK: return DRMP3_ERROR;
3002 #endif
3003 #ifdef EBUSY
3004 case EBUSY: return DRMP3_BUSY;
3005 #endif
3006 #ifdef EEXIST
3007 case EEXIST: return DRMP3_ALREADY_EXISTS;
3008 #endif
3009 #ifdef EXDEV
3010 case EXDEV: return DRMP3_ERROR;
3011 #endif
3012 #ifdef ENODEV
3013 case ENODEV: return DRMP3_DOES_NOT_EXIST;
3014 #endif
3015 #ifdef ENOTDIR
3016 case ENOTDIR: return DRMP3_NOT_DIRECTORY;
3017 #endif
3018 #ifdef EISDIR
3019 case EISDIR: return DRMP3_IS_DIRECTORY;
3020 #endif
3021 #ifdef EINVAL
3022 case EINVAL: return DRMP3_INVALID_ARGS;
3023 #endif
3024 #ifdef ENFILE
3025 case ENFILE: return DRMP3_TOO_MANY_OPEN_FILES;
3026 #endif
3027 #ifdef EMFILE
3028 case EMFILE: return DRMP3_TOO_MANY_OPEN_FILES;
3029 #endif
3030 #ifdef ENOTTY
3031 case ENOTTY: return DRMP3_INVALID_OPERATION;
3032 #endif
3033 #ifdef ETXTBSY
3034 case ETXTBSY: return DRMP3_BUSY;
3035 #endif
3036 #ifdef EFBIG
3037 case EFBIG: return DRMP3_TOO_BIG;
3038 #endif
3039 #ifdef ENOSPC
3040 case ENOSPC: return DRMP3_NO_SPACE;
3041 #endif
3042 #ifdef ESPIPE
3043 case ESPIPE: return DRMP3_BAD_SEEK;
3044 #endif
3045 #ifdef EROFS
3046 case EROFS: return DRMP3_ACCESS_DENIED;
3047 #endif
3048 #ifdef EMLINK
3049 case EMLINK: return DRMP3_TOO_MANY_LINKS;
3050 #endif
3051 #ifdef EPIPE
3052 case EPIPE: return DRMP3_BAD_PIPE;
3053 #endif
3054 #ifdef EDOM
3055 case EDOM: return DRMP3_OUT_OF_RANGE;
3056 #endif
3057 #ifdef ERANGE
3058 case ERANGE: return DRMP3_OUT_OF_RANGE;
3059 #endif
3060 #ifdef EDEADLK
3061 case EDEADLK: return DRMP3_DEADLOCK;
3062 #endif
3063 #ifdef ENAMETOOLONG
3064 case ENAMETOOLONG: return DRMP3_PATH_TOO_LONG;
3065 #endif
3066 #ifdef ENOLCK
3067 case ENOLCK: return DRMP3_ERROR;
3068 #endif
3069 #ifdef ENOSYS
3070 case ENOSYS: return DRMP3_NOT_IMPLEMENTED;
3071 #endif
3072 #ifdef ENOTEMPTY
3073 case ENOTEMPTY: return DRMP3_DIRECTORY_NOT_EMPTY;
3074 #endif
3075 #ifdef ELOOP
3076 case ELOOP: return DRMP3_TOO_MANY_LINKS;
3077 #endif
3078 #ifdef ENOMSG
3079 case ENOMSG: return DRMP3_NO_MESSAGE;
3080 #endif
3081 #ifdef EIDRM
3082 case EIDRM: return DRMP3_ERROR;
3083 #endif
3084 #ifdef ECHRNG
3085 case ECHRNG: return DRMP3_ERROR;
3086 #endif
3087 #ifdef EL2NSYNC
3088 case EL2NSYNC: return DRMP3_ERROR;
3089 #endif
3090 #ifdef EL3HLT
3091 case EL3HLT: return DRMP3_ERROR;
3092 #endif
3093 #ifdef EL3RST
3094 case EL3RST: return DRMP3_ERROR;
3095 #endif
3096 #ifdef ELNRNG
3097 case ELNRNG: return DRMP3_OUT_OF_RANGE;
3098 #endif
3099 #ifdef EUNATCH
3100 case EUNATCH: return DRMP3_ERROR;
3101 #endif
3102 #ifdef ENOCSI
3103 case ENOCSI: return DRMP3_ERROR;
3104 #endif
3105 #ifdef EL2HLT
3106 case EL2HLT: return DRMP3_ERROR;
3107 #endif
3108 #ifdef EBADE
3109 case EBADE: return DRMP3_ERROR;
3110 #endif
3111 #ifdef EBADR
3112 case EBADR: return DRMP3_ERROR;
3113 #endif
3114 #ifdef EXFULL
3115 case EXFULL: return DRMP3_ERROR;
3116 #endif
3117 #ifdef ENOANO
3118 case ENOANO: return DRMP3_ERROR;
3119 #endif
3120 #ifdef EBADRQC
3121 case EBADRQC: return DRMP3_ERROR;
3122 #endif
3123 #ifdef EBADSLT
3124 case EBADSLT: return DRMP3_ERROR;
3125 #endif
3126 #ifdef EBFONT
3127 case EBFONT: return DRMP3_INVALID_FILE;
3128 #endif
3129 #ifdef ENOSTR
3130 case ENOSTR: return DRMP3_ERROR;
3131 #endif
3132 #ifdef ENODATA
3133 case ENODATA: return DRMP3_NO_DATA_AVAILABLE;
3134 #endif
3135 #ifdef ETIME
3136 case ETIME: return DRMP3_TIMEOUT;
3137 #endif
3138 #ifdef ENOSR
3139 case ENOSR: return DRMP3_NO_DATA_AVAILABLE;
3140 #endif
3141 #ifdef ENONET
3142 case ENONET: return DRMP3_NO_NETWORK;
3143 #endif
3144 #ifdef ENOPKG
3145 case ENOPKG: return DRMP3_ERROR;
3146 #endif
3147 #ifdef EREMOTE
3148 case EREMOTE: return DRMP3_ERROR;
3149 #endif
3150 #ifdef ENOLINK
3151 case ENOLINK: return DRMP3_ERROR;
3152 #endif
3153 #ifdef EADV
3154 case EADV: return DRMP3_ERROR;
3155 #endif
3156 #ifdef ESRMNT
3157 case ESRMNT: return DRMP3_ERROR;
3158 #endif
3159 #ifdef ECOMM
3160 case ECOMM: return DRMP3_ERROR;
3161 #endif
3162 #ifdef EPROTO
3163 case EPROTO: return DRMP3_ERROR;
3164 #endif
3165 #ifdef EMULTIHOP
3166 case EMULTIHOP: return DRMP3_ERROR;
3167 #endif
3168 #ifdef EDOTDOT
3169 case EDOTDOT: return DRMP3_ERROR;
3170 #endif
3171 #ifdef EBADMSG
3172 case EBADMSG: return DRMP3_BAD_MESSAGE;
3173 #endif
3174 #ifdef EOVERFLOW
3175 case EOVERFLOW: return DRMP3_TOO_BIG;
3176 #endif
3177 #ifdef ENOTUNIQ
3178 case ENOTUNIQ: return DRMP3_NOT_UNIQUE;
3179 #endif
3180 #ifdef EBADFD
3181 case EBADFD: return DRMP3_ERROR;
3182 #endif
3183 #ifdef EREMCHG
3184 case EREMCHG: return DRMP3_ERROR;
3185 #endif
3186 #ifdef ELIBACC
3187 case ELIBACC: return DRMP3_ACCESS_DENIED;
3188 #endif
3189 #ifdef ELIBBAD
3190 case ELIBBAD: return DRMP3_INVALID_FILE;
3191 #endif
3192 #ifdef ELIBSCN
3193 case ELIBSCN: return DRMP3_INVALID_FILE;
3194 #endif
3195 #ifdef ELIBMAX
3196 case ELIBMAX: return DRMP3_ERROR;
3197 #endif
3198 #ifdef ELIBEXEC
3199 case ELIBEXEC: return DRMP3_ERROR;
3200 #endif
3201 #ifdef EILSEQ
3202 case EILSEQ: return DRMP3_INVALID_DATA;
3203 #endif
3204 #ifdef ERESTART
3205 case ERESTART: return DRMP3_ERROR;
3206 #endif
3207 #ifdef ESTRPIPE
3208 case ESTRPIPE: return DRMP3_ERROR;
3209 #endif
3210 #ifdef EUSERS
3211 case EUSERS: return DRMP3_ERROR;
3212 #endif
3213 #ifdef ENOTSOCK
3214 case ENOTSOCK: return DRMP3_NOT_SOCKET;
3215 #endif
3216 #ifdef EDESTADDRREQ
3217 case EDESTADDRREQ: return DRMP3_NO_ADDRESS;
3218 #endif
3219 #ifdef EMSGSIZE
3220 case EMSGSIZE: return DRMP3_TOO_BIG;
3221 #endif
3222 #ifdef EPROTOTYPE
3223 case EPROTOTYPE: return DRMP3_BAD_PROTOCOL;
3224 #endif
3225 #ifdef ENOPROTOOPT
3226 case ENOPROTOOPT: return DRMP3_PROTOCOL_UNAVAILABLE;
3227 #endif
3228 #ifdef EPROTONOSUPPORT
3229 case EPROTONOSUPPORT: return DRMP3_PROTOCOL_NOT_SUPPORTED;
3230 #endif
3231 #ifdef ESOCKTNOSUPPORT
3232 case ESOCKTNOSUPPORT: return DRMP3_SOCKET_NOT_SUPPORTED;
3233 #endif
3234 #ifdef EOPNOTSUPP
3235 case EOPNOTSUPP: return DRMP3_INVALID_OPERATION;
3236 #endif
3237 #ifdef EPFNOSUPPORT
3238 case EPFNOSUPPORT: return DRMP3_PROTOCOL_FAMILY_NOT_SUPPORTED;
3239 #endif
3240 #ifdef EAFNOSUPPORT
3241 case EAFNOSUPPORT: return DRMP3_ADDRESS_FAMILY_NOT_SUPPORTED;
3242 #endif
3243 #ifdef EADDRINUSE
3244 case EADDRINUSE: return DRMP3_ALREADY_IN_USE;
3245 #endif
3246 #ifdef EADDRNOTAVAIL
3247 case EADDRNOTAVAIL: return DRMP3_ERROR;
3248 #endif
3249 #ifdef ENETDOWN
3250 case ENETDOWN: return DRMP3_NO_NETWORK;
3251 #endif
3252 #ifdef ENETUNREACH
3253 case ENETUNREACH: return DRMP3_NO_NETWORK;
3254 #endif
3255 #ifdef ENETRESET
3256 case ENETRESET: return DRMP3_NO_NETWORK;
3257 #endif
3258 #ifdef ECONNABORTED
3259 case ECONNABORTED: return DRMP3_NO_NETWORK;
3260 #endif
3261 #ifdef ECONNRESET
3262 case ECONNRESET: return DRMP3_CONNECTION_RESET;
3263 #endif
3264 #ifdef ENOBUFS
3265 case ENOBUFS: return DRMP3_NO_SPACE;
3266 #endif
3267 #ifdef EISCONN
3268 case EISCONN: return DRMP3_ALREADY_CONNECTED;
3269 #endif
3270 #ifdef ENOTCONN
3271 case ENOTCONN: return DRMP3_NOT_CONNECTED;
3272 #endif
3273 #ifdef ESHUTDOWN
3274 case ESHUTDOWN: return DRMP3_ERROR;
3275 #endif
3276 #ifdef ETOOMANYREFS
3277 case ETOOMANYREFS: return DRMP3_ERROR;
3278 #endif
3279 #ifdef ETIMEDOUT
3280 case ETIMEDOUT: return DRMP3_TIMEOUT;
3281 #endif
3282 #ifdef ECONNREFUSED
3283 case ECONNREFUSED: return DRMP3_CONNECTION_REFUSED;
3284 #endif
3285 #ifdef EHOSTDOWN
3286 case EHOSTDOWN: return DRMP3_NO_HOST;
3287 #endif
3288 #ifdef EHOSTUNREACH
3289 case EHOSTUNREACH: return DRMP3_NO_HOST;
3290 #endif
3291 #ifdef EALREADY
3292 case EALREADY: return DRMP3_IN_PROGRESS;
3293 #endif
3294 #ifdef EINPROGRESS
3295 case EINPROGRESS: return DRMP3_IN_PROGRESS;
3296 #endif
3297 #ifdef ESTALE
3298 case ESTALE: return DRMP3_INVALID_FILE;
3299 #endif
3300 #ifdef EUCLEAN
3301 case EUCLEAN: return DRMP3_ERROR;
3302 #endif
3303 #ifdef ENOTNAM
3304 case ENOTNAM: return DRMP3_ERROR;
3305 #endif
3306 #ifdef ENAVAIL
3307 case ENAVAIL: return DRMP3_ERROR;
3308 #endif
3309 #ifdef EISNAM
3310 case EISNAM: return DRMP3_ERROR;
3311 #endif
3312 #ifdef EREMOTEIO
3313 case EREMOTEIO: return DRMP3_IO_ERROR;
3314 #endif
3315 #ifdef EDQUOT
3316 case EDQUOT: return DRMP3_NO_SPACE;
3317 #endif
3318 #ifdef ENOMEDIUM
3319 case ENOMEDIUM: return DRMP3_DOES_NOT_EXIST;
3320 #endif
3321 #ifdef EMEDIUMTYPE
3322 case EMEDIUMTYPE: return DRMP3_ERROR;
3323 #endif
3324 #ifdef ECANCELED
3325 case ECANCELED: return DRMP3_CANCELLED;
3326 #endif
3327 #ifdef ENOKEY
3328 case ENOKEY: return DRMP3_ERROR;
3329 #endif
3330 #ifdef EKEYEXPIRED
3331 case EKEYEXPIRED: return DRMP3_ERROR;
3332 #endif
3333 #ifdef EKEYREVOKED
3334 case EKEYREVOKED: return DRMP3_ERROR;
3335 #endif
3336 #ifdef EKEYREJECTED
3337 case EKEYREJECTED: return DRMP3_ERROR;
3338 #endif
3339 #ifdef EOWNERDEAD
3340 case EOWNERDEAD: return DRMP3_ERROR;
3341 #endif
3342 #ifdef ENOTRECOVERABLE
3343 case ENOTRECOVERABLE: return DRMP3_ERROR;
3344 #endif
3345 #ifdef ERFKILL
3346 case ERFKILL: return DRMP3_ERROR;
3347 #endif
3348 #ifdef EHWPOISON
3349 case EHWPOISON: return DRMP3_ERROR;
3350 #endif
3351 default: return DRMP3_ERROR;
3352 }
3353}
3354/* End Errno */
3355
3356/* fopen */
3357static drmp3_result drmp3_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
3358{
3359#if defined(_MSC_VER) && _MSC_VER >= 1400
3360 errno_t err;
3361#endif
3362
3363 if (ppFile != NULL) {
3364 *ppFile = NULL; /* Safety. */
3365 }
3366
3367 if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
3368 return DRMP3_INVALID_ARGS;
3369 }
3370
3371#if defined(_MSC_VER) && _MSC_VER >= 1400
3372 err = fopen_s(ppFile, pFilePath, pOpenMode);
3373 if (err != 0) {
3374 return drmp3_result_from_errno(err);
3375 }
3376#else
3377#if defined(_WIN32) || defined(__APPLE__)
3378 *ppFile = fopen(pFilePath, pOpenMode);
3379#else
3380 #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE)
3381 *ppFile = fopen64(pFilePath, pOpenMode);
3382 #else
3383 *ppFile = fopen(pFilePath, pOpenMode);
3384 #endif
3385#endif
3386 if (*ppFile == NULL) {
3387 drmp3_result result = drmp3_result_from_errno(errno);
3388 if (result == DRMP3_SUCCESS) {
3389 result = DRMP3_ERROR; /* Just a safety check to make sure we never ever return success when pFile == NULL. */
3390 }
3391
3392 return result;
3393 }
3394#endif
3395
3396 return DRMP3_SUCCESS;
3397}
3398
3399/*
3400_wfopen() isn't always available in all compilation environments.
3401
3402 * Windows only.
3403 * MSVC seems to support it universally as far back as VC6 from what I can tell (haven't checked further back).
3404 * MinGW-64 (both 32- and 64-bit) seems to support it.
3405 * MinGW wraps it in !defined(__STRICT_ANSI__).
3406 * OpenWatcom wraps it in !defined(_NO_EXT_KEYS).
3407
3408This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs()
3409fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support.
3410*/
3411#if defined(_WIN32)
3412 #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS))
3413 #define DRMP3_HAS_WFOPEN
3414 #endif
3415#endif
3416
3417static drmp3_result drmp3_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drmp3_allocation_callbacks* pAllocationCallbacks)
3418{
3419 if (ppFile != NULL) {
3420 *ppFile = NULL; /* Safety. */
3421 }
3422
3423 if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
3424 return DRMP3_INVALID_ARGS;
3425 }
3426
3427#if defined(DRMP3_HAS_WFOPEN)
3428 {
3429 /* Use _wfopen() on Windows. */
3430 #if defined(_MSC_VER) && _MSC_VER >= 1400
3431 errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode);
3432 if (err != 0) {
3433 return drmp3_result_from_errno(err);
3434 }
3435 #else
3436 *ppFile = _wfopen(pFilePath, pOpenMode);
3437 if (*ppFile == NULL) {
3438 return drmp3_result_from_errno(errno);
3439 }
3440 #endif
3441 (void)pAllocationCallbacks;
3442 }
3443#else
3444 /*
3445 Use fopen() on anything other than Windows. Requires a conversion. This is annoying because
3446 fopen() is locale specific. The only real way I can think of to do this is with wcsrtombs(). Note
3447 that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for
3448 maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler
3449 error I'll look into improving compatibility.
3450 */
3451
3452 /*
3453 Some compilers don't support wchar_t or wcsrtombs() which we're using below. In this case we just
3454 need to abort with an error. If you encounter a compiler lacking such support, add it to this list
3455 and submit a bug report and it'll be added to the library upstream.
3456 */
3457 #if defined(__DJGPP__)
3458 {
3459 /* Nothing to do here. This will fall through to the error check below. */
3460 }
3461 #else
3462 {
3463 mbstate_t mbs;
3464 size_t lenMB;
3465 const wchar_t* pFilePathTemp = pFilePath;
3466 char* pFilePathMB = NULL;
3467 char pOpenModeMB[32] = {0};
3468
3469 /* Get the length first. */
3470 DRMP3_ZERO_OBJECT(&mbs);
3471 lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs);
3472 if (lenMB == (size_t)-1) {
3473 return drmp3_result_from_errno(errno);
3474 }
3475
3476 pFilePathMB = (char*)drmp3__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks);
3477 if (pFilePathMB == NULL) {
3478 return DRMP3_OUT_OF_MEMORY;
3479 }
3480
3481 pFilePathTemp = pFilePath;
3482 DRMP3_ZERO_OBJECT(&mbs);
3483 wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs);
3484
3485 /* The open mode should always consist of ASCII characters so we should be able to do a trivial conversion. */
3486 {
3487 size_t i = 0;
3488 for (;;) {
3489 if (pOpenMode[i] == 0) {
3490 pOpenModeMB[i] = '\0';
3491 break;
3492 }
3493
3494 pOpenModeMB[i] = (char)pOpenMode[i];
3495 i += 1;
3496 }
3497 }
3498
3499 *ppFile = fopen(pFilePathMB, pOpenModeMB);
3500
3501 drmp3__free_from_callbacks(pFilePathMB, pAllocationCallbacks);
3502 }
3503 #endif
3504
3505 if (*ppFile == NULL) {
3506 return DRMP3_ERROR;
3507 }
3508#endif
3509
3510 return DRMP3_SUCCESS;
3511}
3512/* End fopen */
3513
3514
3515static size_t drmp3__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead)
3516{
3517 return fread(pBufferOut, 1, bytesToRead, (FILE*)pUserData);
3518}
3519
3520static drmp3_bool32 drmp3__on_seek_stdio(void* pUserData, int offset, drmp3_seek_origin origin)
3521{
3522 return fseek((FILE*)pUserData, offset, (origin == drmp3_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
3523}
3524
3525DRMP3_API drmp3_bool32 drmp3_init_file(drmp3* pMP3, const char* pFilePath, const drmp3_allocation_callbacks* pAllocationCallbacks)
3526{
3527 drmp3_bool32 result;
3528 FILE* pFile;
3529
3530 if (drmp3_fopen(&pFile, pFilePath, "rb") != DRMP3_SUCCESS) {
3531 return DRMP3_FALSE;
3532 }
3533
3534 result = drmp3_init(pMP3, drmp3__on_read_stdio, drmp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
3535 if (result != DRMP3_TRUE) {
3536 fclose(pFile);
3537 return result;
3538 }
3539
3540 return DRMP3_TRUE;
3541}
3542
3543DRMP3_API drmp3_bool32 drmp3_init_file_w(drmp3* pMP3, const wchar_t* pFilePath, const drmp3_allocation_callbacks* pAllocationCallbacks)
3544{
3545 drmp3_bool32 result;
3546 FILE* pFile;
3547
3548 if (drmp3_wfopen(&pFile, pFilePath, L"rb", pAllocationCallbacks) != DRMP3_SUCCESS) {
3549 return DRMP3_FALSE;
3550 }
3551
3552 result = drmp3_init(pMP3, drmp3__on_read_stdio, drmp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
3553 if (result != DRMP3_TRUE) {
3554 fclose(pFile);
3555 return result;
3556 }
3557
3558 return DRMP3_TRUE;
3559}
3560#endif
3561
3562DRMP3_API void drmp3_uninit(drmp3* pMP3)
3563{
3564 if (pMP3 == NULL) {
3565 return;
3566 }
3567
3568#ifndef DR_MP3_NO_STDIO
3569 if (pMP3->onRead == drmp3__on_read_stdio) {
3570 FILE* pFile = (FILE*)pMP3->pUserData;
3571 if (pFile != NULL) {
3572 fclose(pFile);
3573 pMP3->pUserData = NULL; /* Make sure the file handle is cleared to NULL to we don't attempt to close it a second time. */
3574 }
3575 }
3576#endif
3577
3578 drmp3__free_from_callbacks(pMP3->pData, &pMP3->allocationCallbacks);
3579}
3580
3581#if defined(DR_MP3_FLOAT_OUTPUT)
3582static void drmp3_f32_to_s16(drmp3_int16* dst, const float* src, drmp3_uint64 sampleCount)
3583{
3584 drmp3_uint64 i;
3585 drmp3_uint64 i4;
3586 drmp3_uint64 sampleCount4;
3587
3588 /* Unrolled. */
3589 i = 0;
3590 sampleCount4 = sampleCount >> 2;
3591 for (i4 = 0; i4 < sampleCount4; i4 += 1) {
3592 float x0 = src[i+0];
3593 float x1 = src[i+1];
3594 float x2 = src[i+2];
3595 float x3 = src[i+3];
3596
3597 x0 = ((x0 < -1) ? -1 : ((x0 > 1) ? 1 : x0));
3598 x1 = ((x1 < -1) ? -1 : ((x1 > 1) ? 1 : x1));
3599 x2 = ((x2 < -1) ? -1 : ((x2 > 1) ? 1 : x2));
3600 x3 = ((x3 < -1) ? -1 : ((x3 > 1) ? 1 : x3));
3601
3602 x0 = x0 * 32767.0f;
3603 x1 = x1 * 32767.0f;
3604 x2 = x2 * 32767.0f;
3605 x3 = x3 * 32767.0f;
3606
3607 dst[i+0] = (drmp3_int16)x0;
3608 dst[i+1] = (drmp3_int16)x1;
3609 dst[i+2] = (drmp3_int16)x2;
3610 dst[i+3] = (drmp3_int16)x3;
3611
3612 i += 4;
3613 }
3614
3615 /* Leftover. */
3616 for (; i < sampleCount; i += 1) {
3617 float x = src[i];
3618 x = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); /* clip */
3619 x = x * 32767.0f; /* -1..1 to -32767..32767 */
3620
3621 dst[i] = (drmp3_int16)x;
3622 }
3623}
3624#endif
3625
3626#if !defined(DR_MP3_FLOAT_OUTPUT)
3627static void drmp3_s16_to_f32(float* dst, const drmp3_int16* src, drmp3_uint64 sampleCount)
3628{
3629 drmp3_uint64 i;
3630 for (i = 0; i < sampleCount; i += 1) {
3631 float x = (float)src[i];
3632 x = x * 0.000030517578125f; /* -32768..32767 to -1..0.999969482421875 */
3633 dst[i] = x;
3634 }
3635}
3636#endif
3637
3638
3639static drmp3_uint64 drmp3_read_pcm_frames_raw(drmp3* pMP3, drmp3_uint64 framesToRead, void* pBufferOut)
3640{
3641 drmp3_uint64 totalFramesRead = 0;
3642
3643 DRMP3_ASSERT(pMP3 != NULL);
3644 DRMP3_ASSERT(pMP3->onRead != NULL);
3645
3646 while (framesToRead > 0) {
3647 drmp3_uint32 framesToConsume = (drmp3_uint32)DRMP3_MIN(pMP3->pcmFramesRemainingInMP3Frame, framesToRead);
3648 if (pBufferOut != NULL) {
3649 #if defined(DR_MP3_FLOAT_OUTPUT)
3650 /* f32 */
3651 float* pFramesOutF32 = (float*)DRMP3_OFFSET_PTR(pBufferOut, sizeof(float) * totalFramesRead * pMP3->channels);
3652 float* pFramesInF32 = (float*)DRMP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(float) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels);
3653 DRMP3_COPY_MEMORY(pFramesOutF32, pFramesInF32, sizeof(float) * framesToConsume * pMP3->channels);
3654 #else
3655 /* s16 */
3656 drmp3_int16* pFramesOutS16 = (drmp3_int16*)DRMP3_OFFSET_PTR(pBufferOut, sizeof(drmp3_int16) * totalFramesRead * pMP3->channels);
3657 drmp3_int16* pFramesInS16 = (drmp3_int16*)DRMP3_OFFSET_PTR(&pMP3->pcmFrames[0], sizeof(drmp3_int16) * pMP3->pcmFramesConsumedInMP3Frame * pMP3->mp3FrameChannels);
3658 DRMP3_COPY_MEMORY(pFramesOutS16, pFramesInS16, sizeof(drmp3_int16) * framesToConsume * pMP3->channels);
3659 #endif
3660 }
3661
3662 pMP3->currentPCMFrame += framesToConsume;
3663 pMP3->pcmFramesConsumedInMP3Frame += framesToConsume;
3664 pMP3->pcmFramesRemainingInMP3Frame -= framesToConsume;
3665 totalFramesRead += framesToConsume;
3666 framesToRead -= framesToConsume;
3667
3668 if (framesToRead == 0) {
3669 break;
3670 }
3671
3672 DRMP3_ASSERT(pMP3->pcmFramesRemainingInMP3Frame == 0);
3673
3674 /*
3675 At this point we have exhausted our in-memory buffer so we need to re-fill. Note that the sample rate may have changed
3676 at this point which means we'll also need to update our sample rate conversion pipeline.
3677 */
3678 if (drmp3_decode_next_frame(pMP3) == 0) {
3679 break;
3680 }
3681 }
3682
3683 return totalFramesRead;
3684}
3685
3686
3687DRMP3_API drmp3_uint64 drmp3_read_pcm_frames_f32(drmp3* pMP3, drmp3_uint64 framesToRead, float* pBufferOut)
3688{
3689 if (pMP3 == NULL || pMP3->onRead == NULL) {
3690 return 0;
3691 }
3692
3693#if defined(DR_MP3_FLOAT_OUTPUT)
3694 /* Fast path. No conversion required. */
3695 return drmp3_read_pcm_frames_raw(pMP3, framesToRead, pBufferOut);
3696#else
3697 /* Slow path. Convert from s16 to f32. */
3698 {
3699 drmp3_int16 pTempS16[8192];
3700 drmp3_uint64 totalPCMFramesRead = 0;
3701
3702 while (totalPCMFramesRead < framesToRead) {
3703 drmp3_uint64 framesJustRead;
3704 drmp3_uint64 framesRemaining = framesToRead - totalPCMFramesRead;
3705 drmp3_uint64 framesToReadNow = DRMP3_COUNTOF(pTempS16) / pMP3->channels;
3706 if (framesToReadNow > framesRemaining) {
3707 framesToReadNow = framesRemaining;
3708 }
3709
3710 framesJustRead = drmp3_read_pcm_frames_raw(pMP3, framesToReadNow, pTempS16);
3711 if (framesJustRead == 0) {
3712 break;
3713 }
3714
3715 drmp3_s16_to_f32((float*)DRMP3_OFFSET_PTR(pBufferOut, sizeof(float) * totalPCMFramesRead * pMP3->channels), pTempS16, framesJustRead * pMP3->channels);
3716 totalPCMFramesRead += framesJustRead;
3717 }
3718
3719 return totalPCMFramesRead;
3720 }
3721#endif
3722}
3723
3724DRMP3_API drmp3_uint64 drmp3_read_pcm_frames_s16(drmp3* pMP3, drmp3_uint64 framesToRead, drmp3_int16* pBufferOut)
3725{
3726 if (pMP3 == NULL || pMP3->onRead == NULL) {
3727 return 0;
3728 }
3729
3730#if !defined(DR_MP3_FLOAT_OUTPUT)
3731 /* Fast path. No conversion required. */
3732 return drmp3_read_pcm_frames_raw(pMP3, framesToRead, pBufferOut);
3733#else
3734 /* Slow path. Convert from f32 to s16. */
3735 {
3736 float pTempF32[4096];
3737 drmp3_uint64 totalPCMFramesRead = 0;
3738
3739 while (totalPCMFramesRead < framesToRead) {
3740 drmp3_uint64 framesJustRead;
3741 drmp3_uint64 framesRemaining = framesToRead - totalPCMFramesRead;
3742 drmp3_uint64 framesToReadNow = DRMP3_COUNTOF(pTempF32) / pMP3->channels;
3743 if (framesToReadNow > framesRemaining) {
3744 framesToReadNow = framesRemaining;
3745 }
3746
3747 framesJustRead = drmp3_read_pcm_frames_raw(pMP3, framesToReadNow, pTempF32);
3748 if (framesJustRead == 0) {
3749 break;
3750 }
3751
3752 drmp3_f32_to_s16((drmp3_int16*)DRMP3_OFFSET_PTR(pBufferOut, sizeof(drmp3_int16) * totalPCMFramesRead * pMP3->channels), pTempF32, framesJustRead * pMP3->channels);
3753 totalPCMFramesRead += framesJustRead;
3754 }
3755
3756 return totalPCMFramesRead;
3757 }
3758#endif
3759}
3760
3761static void drmp3_reset(drmp3* pMP3)
3762{
3763 DRMP3_ASSERT(pMP3 != NULL);
3764
3765 pMP3->pcmFramesConsumedInMP3Frame = 0;
3766 pMP3->pcmFramesRemainingInMP3Frame = 0;
3767 pMP3->currentPCMFrame = 0;
3768 pMP3->dataSize = 0;
3769 pMP3->atEnd = DRMP3_FALSE;
3770 drmp3dec_init(&pMP3->decoder);
3771}
3772
3773static drmp3_bool32 drmp3_seek_to_start_of_stream(drmp3* pMP3)
3774{
3775 DRMP3_ASSERT(pMP3 != NULL);
3776 DRMP3_ASSERT(pMP3->onSeek != NULL);
3777
3778 /* Seek to the start of the stream to begin with. */
3779 if (!drmp3__on_seek(pMP3, 0, drmp3_seek_origin_start)) {
3780 return DRMP3_FALSE;
3781 }
3782
3783 /* Clear any cached data. */
3784 drmp3_reset(pMP3);
3785 return DRMP3_TRUE;
3786}
3787
3788
3789static drmp3_bool32 drmp3_seek_forward_by_pcm_frames__brute_force(drmp3* pMP3, drmp3_uint64 frameOffset)
3790{
3791 drmp3_uint64 framesRead;
3792
3793 /*
3794 Just using a dumb read-and-discard for now. What would be nice is to parse only the header of the MP3 frame, and then skip over leading
3795 frames without spending the time doing a full decode. I cannot see an easy way to do this in minimp3, however, so it may involve some
3796 kind of manual processing.
3797 */
3798#if defined(DR_MP3_FLOAT_OUTPUT)
3799 framesRead = drmp3_read_pcm_frames_f32(pMP3, frameOffset, NULL);
3800#else
3801 framesRead = drmp3_read_pcm_frames_s16(pMP3, frameOffset, NULL);
3802#endif
3803 if (framesRead != frameOffset) {
3804 return DRMP3_FALSE;
3805 }
3806
3807 return DRMP3_TRUE;
3808}
3809
3810static drmp3_bool32 drmp3_seek_to_pcm_frame__brute_force(drmp3* pMP3, drmp3_uint64 frameIndex)
3811{
3812 DRMP3_ASSERT(pMP3 != NULL);
3813
3814 if (frameIndex == pMP3->currentPCMFrame) {
3815 return DRMP3_TRUE;
3816 }
3817
3818 /*
3819 If we're moving foward we just read from where we're at. Otherwise we need to move back to the start of
3820 the stream and read from the beginning.
3821 */
3822 if (frameIndex < pMP3->currentPCMFrame) {
3823 /* Moving backward. Move to the start of the stream and then move forward. */
3824 if (!drmp3_seek_to_start_of_stream(pMP3)) {
3825 return DRMP3_FALSE;
3826 }
3827 }
3828
3829 DRMP3_ASSERT(frameIndex >= pMP3->currentPCMFrame);
3830 return drmp3_seek_forward_by_pcm_frames__brute_force(pMP3, (frameIndex - pMP3->currentPCMFrame));
3831}
3832
3833static drmp3_bool32 drmp3_find_closest_seek_point(drmp3* pMP3, drmp3_uint64 frameIndex, drmp3_uint32* pSeekPointIndex)
3834{
3835 drmp3_uint32 iSeekPoint;
3836
3837 DRMP3_ASSERT(pSeekPointIndex != NULL);
3838
3839 *pSeekPointIndex = 0;
3840
3841 if (frameIndex < pMP3->pSeekPoints[0].pcmFrameIndex) {
3842 return DRMP3_FALSE;
3843 }
3844
3845 /* Linear search for simplicity to begin with while I'm getting this thing working. Once it's all working change this to a binary search. */
3846 for (iSeekPoint = 0; iSeekPoint < pMP3->seekPointCount; ++iSeekPoint) {
3847 if (pMP3->pSeekPoints[iSeekPoint].pcmFrameIndex > frameIndex) {
3848 break; /* Found it. */
3849 }
3850
3851 *pSeekPointIndex = iSeekPoint;
3852 }
3853
3854 return DRMP3_TRUE;
3855}
3856
3857static drmp3_bool32 drmp3_seek_to_pcm_frame__seek_table(drmp3* pMP3, drmp3_uint64 frameIndex)
3858{
3859 drmp3_seek_point seekPoint;
3860 drmp3_uint32 priorSeekPointIndex;
3861 drmp3_uint16 iMP3Frame;
3862 drmp3_uint64 leftoverFrames;
3863
3864 DRMP3_ASSERT(pMP3 != NULL);
3865 DRMP3_ASSERT(pMP3->pSeekPoints != NULL);
3866 DRMP3_ASSERT(pMP3->seekPointCount > 0);
3867
3868 /* If there is no prior seekpoint it means the target PCM frame comes before the first seek point. Just assume a seekpoint at the start of the file in this case. */
3869 if (drmp3_find_closest_seek_point(pMP3, frameIndex, &priorSeekPointIndex)) {
3870 seekPoint = pMP3->pSeekPoints[priorSeekPointIndex];
3871 } else {
3872 seekPoint.seekPosInBytes = 0;
3873 seekPoint.pcmFrameIndex = 0;
3874 seekPoint.mp3FramesToDiscard = 0;
3875 seekPoint.pcmFramesToDiscard = 0;
3876 }
3877
3878 /* First thing to do is seek to the first byte of the relevant MP3 frame. */
3879 if (!drmp3__on_seek_64(pMP3, seekPoint.seekPosInBytes, drmp3_seek_origin_start)) {
3880 return DRMP3_FALSE; /* Failed to seek. */
3881 }
3882
3883 /* Clear any cached data. */
3884 drmp3_reset(pMP3);
3885
3886 /* Whole MP3 frames need to be discarded first. */
3887 for (iMP3Frame = 0; iMP3Frame < seekPoint.mp3FramesToDiscard; ++iMP3Frame) {
3888 drmp3_uint32 pcmFramesRead;
3889 drmp3d_sample_t* pPCMFrames;
3890
3891 /* Pass in non-null for the last frame because we want to ensure the sample rate converter is preloaded correctly. */
3892 pPCMFrames = NULL;
3893 if (iMP3Frame == seekPoint.mp3FramesToDiscard-1) {
3894 pPCMFrames = (drmp3d_sample_t*)pMP3->pcmFrames;
3895 }
3896
3897 /* We first need to decode the next frame. */
3898 pcmFramesRead = drmp3_decode_next_frame_ex(pMP3, pPCMFrames);
3899 if (pcmFramesRead == 0) {
3900 return DRMP3_FALSE;
3901 }
3902 }
3903
3904 /* We seeked to an MP3 frame in the raw stream so we need to make sure the current PCM frame is set correctly. */
3905 pMP3->currentPCMFrame = seekPoint.pcmFrameIndex - seekPoint.pcmFramesToDiscard;
3906
3907 /*
3908 Now at this point we can follow the same process as the brute force technique where we just skip over unnecessary MP3 frames and then
3909 read-and-discard at least 2 whole MP3 frames.
3910 */
3911 leftoverFrames = frameIndex - pMP3->currentPCMFrame;
3912 return drmp3_seek_forward_by_pcm_frames__brute_force(pMP3, leftoverFrames);
3913}
3914
3915DRMP3_API drmp3_bool32 drmp3_seek_to_pcm_frame(drmp3* pMP3, drmp3_uint64 frameIndex)
3916{
3917 if (pMP3 == NULL || pMP3->onSeek == NULL) {
3918 return DRMP3_FALSE;
3919 }
3920
3921 if (frameIndex == 0) {
3922 return drmp3_seek_to_start_of_stream(pMP3);
3923 }
3924
3925 /* Use the seek table if we have one. */
3926 if (pMP3->pSeekPoints != NULL && pMP3->seekPointCount > 0) {
3927 return drmp3_seek_to_pcm_frame__seek_table(pMP3, frameIndex);
3928 } else {
3929 return drmp3_seek_to_pcm_frame__brute_force(pMP3, frameIndex);
3930 }
3931}
3932
3933DRMP3_API drmp3_bool32 drmp3_get_mp3_and_pcm_frame_count(drmp3* pMP3, drmp3_uint64* pMP3FrameCount, drmp3_uint64* pPCMFrameCount)
3934{
3935 drmp3_uint64 currentPCMFrame;
3936 drmp3_uint64 totalPCMFrameCount;
3937 drmp3_uint64 totalMP3FrameCount;
3938
3939 if (pMP3 == NULL) {
3940 return DRMP3_FALSE;
3941 }
3942
3943 /*
3944 The way this works is we move back to the start of the stream, iterate over each MP3 frame and calculate the frame count based
3945 on our output sample rate, the seek back to the PCM frame we were sitting on before calling this function.
3946 */
3947
3948 /* The stream must support seeking for this to work. */
3949 if (pMP3->onSeek == NULL) {
3950 return DRMP3_FALSE;
3951 }
3952
3953 /* We'll need to seek back to where we were, so grab the PCM frame we're currently sitting on so we can restore later. */
3954 currentPCMFrame = pMP3->currentPCMFrame;
3955
3956 if (!drmp3_seek_to_start_of_stream(pMP3)) {
3957 return DRMP3_FALSE;
3958 }
3959
3960 totalPCMFrameCount = 0;
3961 totalMP3FrameCount = 0;
3962
3963 for (;;) {
3964 drmp3_uint32 pcmFramesInCurrentMP3Frame;
3965
3966 pcmFramesInCurrentMP3Frame = drmp3_decode_next_frame_ex(pMP3, NULL);
3967 if (pcmFramesInCurrentMP3Frame == 0) {
3968 break;
3969 }
3970
3971 totalPCMFrameCount += pcmFramesInCurrentMP3Frame;
3972 totalMP3FrameCount += 1;
3973 }
3974
3975 /* Finally, we need to seek back to where we were. */
3976 if (!drmp3_seek_to_start_of_stream(pMP3)) {
3977 return DRMP3_FALSE;
3978 }
3979
3980 if (!drmp3_seek_to_pcm_frame(pMP3, currentPCMFrame)) {
3981 return DRMP3_FALSE;
3982 }
3983
3984 if (pMP3FrameCount != NULL) {
3985 *pMP3FrameCount = totalMP3FrameCount;
3986 }
3987 if (pPCMFrameCount != NULL) {
3988 *pPCMFrameCount = totalPCMFrameCount;
3989 }
3990
3991 return DRMP3_TRUE;
3992}
3993
3994DRMP3_API drmp3_uint64 drmp3_get_pcm_frame_count(drmp3* pMP3)
3995{
3996 drmp3_uint64 totalPCMFrameCount;
3997 if (!drmp3_get_mp3_and_pcm_frame_count(pMP3, NULL, &totalPCMFrameCount)) {
3998 return 0;
3999 }
4000
4001 return totalPCMFrameCount;
4002}
4003
4004DRMP3_API drmp3_uint64 drmp3_get_mp3_frame_count(drmp3* pMP3)
4005{
4006 drmp3_uint64 totalMP3FrameCount;
4007 if (!drmp3_get_mp3_and_pcm_frame_count(pMP3, &totalMP3FrameCount, NULL)) {
4008 return 0;
4009 }
4010
4011 return totalMP3FrameCount;
4012}
4013
4014static void drmp3__accumulate_running_pcm_frame_count(drmp3* pMP3, drmp3_uint32 pcmFrameCountIn, drmp3_uint64* pRunningPCMFrameCount, float* pRunningPCMFrameCountFractionalPart)
4015{
4016 float srcRatio;
4017 float pcmFrameCountOutF;
4018 drmp3_uint32 pcmFrameCountOut;
4019
4020 srcRatio = (float)pMP3->mp3FrameSampleRate / (float)pMP3->sampleRate;
4021 DRMP3_ASSERT(srcRatio > 0);
4022
4023 pcmFrameCountOutF = *pRunningPCMFrameCountFractionalPart + (pcmFrameCountIn / srcRatio);
4024 pcmFrameCountOut = (drmp3_uint32)pcmFrameCountOutF;
4025 *pRunningPCMFrameCountFractionalPart = pcmFrameCountOutF - pcmFrameCountOut;
4026 *pRunningPCMFrameCount += pcmFrameCountOut;
4027}
4028
4029typedef struct
4030{
4031 drmp3_uint64 bytePos;
4032 drmp3_uint64 pcmFrameIndex; /* <-- After sample rate conversion. */
4033} drmp3__seeking_mp3_frame_info;
4034
4035DRMP3_API drmp3_bool32 drmp3_calculate_seek_points(drmp3* pMP3, drmp3_uint32* pSeekPointCount, drmp3_seek_point* pSeekPoints)
4036{
4037 drmp3_uint32 seekPointCount;
4038 drmp3_uint64 currentPCMFrame;
4039 drmp3_uint64 totalMP3FrameCount;
4040 drmp3_uint64 totalPCMFrameCount;
4041
4042 if (pMP3 == NULL || pSeekPointCount == NULL || pSeekPoints == NULL) {
4043 return DRMP3_FALSE; /* Invalid args. */
4044 }
4045
4046 seekPointCount = *pSeekPointCount;
4047 if (seekPointCount == 0) {
4048 return DRMP3_FALSE; /* The client has requested no seek points. Consider this to be invalid arguments since the client has probably not intended this. */
4049 }
4050
4051 /* We'll need to seek back to the current sample after calculating the seekpoints so we need to go ahead and grab the current location at the top. */
4052 currentPCMFrame = pMP3->currentPCMFrame;
4053
4054 /* We never do more than the total number of MP3 frames and we limit it to 32-bits. */
4055 if (!drmp3_get_mp3_and_pcm_frame_count(pMP3, &totalMP3FrameCount, &totalPCMFrameCount)) {
4056 return DRMP3_FALSE;
4057 }
4058
4059 /* If there's less than DRMP3_SEEK_LEADING_MP3_FRAMES+1 frames we just report 1 seek point which will be the very start of the stream. */
4060 if (totalMP3FrameCount < DRMP3_SEEK_LEADING_MP3_FRAMES+1) {
4061 seekPointCount = 1;
4062 pSeekPoints[0].seekPosInBytes = 0;
4063 pSeekPoints[0].pcmFrameIndex = 0;
4064 pSeekPoints[0].mp3FramesToDiscard = 0;
4065 pSeekPoints[0].pcmFramesToDiscard = 0;
4066 } else {
4067 drmp3_uint64 pcmFramesBetweenSeekPoints;
4068 drmp3__seeking_mp3_frame_info mp3FrameInfo[DRMP3_SEEK_LEADING_MP3_FRAMES+1];
4069 drmp3_uint64 runningPCMFrameCount = 0;
4070 float runningPCMFrameCountFractionalPart = 0;
4071 drmp3_uint64 nextTargetPCMFrame;
4072 drmp3_uint32 iMP3Frame;
4073 drmp3_uint32 iSeekPoint;
4074
4075 if (seekPointCount > totalMP3FrameCount-1) {
4076 seekPointCount = (drmp3_uint32)totalMP3FrameCount-1;
4077 }
4078
4079 pcmFramesBetweenSeekPoints = totalPCMFrameCount / (seekPointCount+1);
4080
4081 /*
4082 Here is where we actually calculate the seek points. We need to start by moving the start of the stream. We then enumerate over each
4083 MP3 frame.
4084 */
4085 if (!drmp3_seek_to_start_of_stream(pMP3)) {
4086 return DRMP3_FALSE;
4087 }
4088
4089 /*
4090 We need to cache the byte positions of the previous MP3 frames. As a new MP3 frame is iterated, we cycle the byte positions in this
4091 array. The value in the first item in this array is the byte position that will be reported in the next seek point.
4092 */
4093
4094 /* We need to initialize the array of MP3 byte positions for the leading MP3 frames. */
4095 for (iMP3Frame = 0; iMP3Frame < DRMP3_SEEK_LEADING_MP3_FRAMES+1; ++iMP3Frame) {
4096 drmp3_uint32 pcmFramesInCurrentMP3FrameIn;
4097
4098 /* The byte position of the next frame will be the stream's cursor position, minus whatever is sitting in the buffer. */
4099 DRMP3_ASSERT(pMP3->streamCursor >= pMP3->dataSize);
4100 mp3FrameInfo[iMP3Frame].bytePos = pMP3->streamCursor - pMP3->dataSize;
4101 mp3FrameInfo[iMP3Frame].pcmFrameIndex = runningPCMFrameCount;
4102
4103 /* We need to get information about this frame so we can know how many samples it contained. */
4104 pcmFramesInCurrentMP3FrameIn = drmp3_decode_next_frame_ex(pMP3, NULL);
4105 if (pcmFramesInCurrentMP3FrameIn == 0) {
4106 return DRMP3_FALSE; /* This should never happen. */
4107 }
4108
4109 drmp3__accumulate_running_pcm_frame_count(pMP3, pcmFramesInCurrentMP3FrameIn, &runningPCMFrameCount, &runningPCMFrameCountFractionalPart);
4110 }
4111
4112 /*
4113 At this point we will have extracted the byte positions of the leading MP3 frames. We can now start iterating over each seek point and
4114 calculate them.
4115 */
4116 nextTargetPCMFrame = 0;
4117 for (iSeekPoint = 0; iSeekPoint < seekPointCount; ++iSeekPoint) {
4118 nextTargetPCMFrame += pcmFramesBetweenSeekPoints;
4119
4120 for (;;) {
4121 if (nextTargetPCMFrame < runningPCMFrameCount) {
4122 /* The next seek point is in the current MP3 frame. */
4123 pSeekPoints[iSeekPoint].seekPosInBytes = mp3FrameInfo[0].bytePos;
4124 pSeekPoints[iSeekPoint].pcmFrameIndex = nextTargetPCMFrame;
4125 pSeekPoints[iSeekPoint].mp3FramesToDiscard = DRMP3_SEEK_LEADING_MP3_FRAMES;
4126 pSeekPoints[iSeekPoint].pcmFramesToDiscard = (drmp3_uint16)(nextTargetPCMFrame - mp3FrameInfo[DRMP3_SEEK_LEADING_MP3_FRAMES-1].pcmFrameIndex);
4127 break;
4128 } else {
4129 size_t i;
4130 drmp3_uint32 pcmFramesInCurrentMP3FrameIn;
4131
4132 /*
4133 The next seek point is not in the current MP3 frame, so continue on to the next one. The first thing to do is cycle the cached
4134 MP3 frame info.
4135 */
4136 for (i = 0; i < DRMP3_COUNTOF(mp3FrameInfo)-1; ++i) {
4137 mp3FrameInfo[i] = mp3FrameInfo[i+1];
4138 }
4139
4140 /* Cache previous MP3 frame info. */
4141 mp3FrameInfo[DRMP3_COUNTOF(mp3FrameInfo)-1].bytePos = pMP3->streamCursor - pMP3->dataSize;
4142 mp3FrameInfo[DRMP3_COUNTOF(mp3FrameInfo)-1].pcmFrameIndex = runningPCMFrameCount;
4143
4144 /*
4145 Go to the next MP3 frame. This shouldn't ever fail, but just in case it does we just set the seek point and break. If it happens, it
4146 should only ever do it for the last seek point.
4147 */
4148 pcmFramesInCurrentMP3FrameIn = drmp3_decode_next_frame_ex(pMP3, NULL);
4149 if (pcmFramesInCurrentMP3FrameIn == 0) {
4150 pSeekPoints[iSeekPoint].seekPosInBytes = mp3FrameInfo[0].bytePos;
4151 pSeekPoints[iSeekPoint].pcmFrameIndex = nextTargetPCMFrame;
4152 pSeekPoints[iSeekPoint].mp3FramesToDiscard = DRMP3_SEEK_LEADING_MP3_FRAMES;
4153 pSeekPoints[iSeekPoint].pcmFramesToDiscard = (drmp3_uint16)(nextTargetPCMFrame - mp3FrameInfo[DRMP3_SEEK_LEADING_MP3_FRAMES-1].pcmFrameIndex);
4154 break;
4155 }
4156
4157 drmp3__accumulate_running_pcm_frame_count(pMP3, pcmFramesInCurrentMP3FrameIn, &runningPCMFrameCount, &runningPCMFrameCountFractionalPart);
4158 }
4159 }
4160 }
4161
4162 /* Finally, we need to seek back to where we were. */
4163 if (!drmp3_seek_to_start_of_stream(pMP3)) {
4164 return DRMP3_FALSE;
4165 }
4166 if (!drmp3_seek_to_pcm_frame(pMP3, currentPCMFrame)) {
4167 return DRMP3_FALSE;
4168 }
4169 }
4170
4171 *pSeekPointCount = seekPointCount;
4172 return DRMP3_TRUE;
4173}
4174
4175DRMP3_API drmp3_bool32 drmp3_bind_seek_table(drmp3* pMP3, drmp3_uint32 seekPointCount, drmp3_seek_point* pSeekPoints)
4176{
4177 if (pMP3 == NULL) {
4178 return DRMP3_FALSE;
4179 }
4180
4181 if (seekPointCount == 0 || pSeekPoints == NULL) {
4182 /* Unbinding. */
4183 pMP3->seekPointCount = 0;
4184 pMP3->pSeekPoints = NULL;
4185 } else {
4186 /* Binding. */
4187 pMP3->seekPointCount = seekPointCount;
4188 pMP3->pSeekPoints = pSeekPoints;
4189 }
4190
4191 return DRMP3_TRUE;
4192}
4193
4194
4195static float* drmp3__full_read_and_close_f32(drmp3* pMP3, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount)
4196{
4197 drmp3_uint64 totalFramesRead = 0;
4198 drmp3_uint64 framesCapacity = 0;
4199 float* pFrames = NULL;
4200 float temp[4096];
4201
4202 DRMP3_ASSERT(pMP3 != NULL);
4203
4204 for (;;) {
4205 drmp3_uint64 framesToReadRightNow = DRMP3_COUNTOF(temp) / pMP3->channels;
4206 drmp3_uint64 framesJustRead = drmp3_read_pcm_frames_f32(pMP3, framesToReadRightNow, temp);
4207 if (framesJustRead == 0) {
4208 break;
4209 }
4210
4211 /* Reallocate the output buffer if there's not enough room. */
4212 if (framesCapacity < totalFramesRead + framesJustRead) {
4213 drmp3_uint64 oldFramesBufferSize;
4214 drmp3_uint64 newFramesBufferSize;
4215 drmp3_uint64 newFramesCap;
4216 float* pNewFrames;
4217
4218 newFramesCap = framesCapacity * 2;
4219 if (newFramesCap < totalFramesRead + framesJustRead) {
4220 newFramesCap = totalFramesRead + framesJustRead;
4221 }
4222
4223 oldFramesBufferSize = framesCapacity * pMP3->channels * sizeof(float);
4224 newFramesBufferSize = newFramesCap * pMP3->channels * sizeof(float);
4225 if (newFramesBufferSize > (drmp3_uint64)DRMP3_SIZE_MAX) {
4226 break;
4227 }
4228
4229 pNewFrames = (float*)drmp3__realloc_from_callbacks(pFrames, (size_t)newFramesBufferSize, (size_t)oldFramesBufferSize, &pMP3->allocationCallbacks);
4230 if (pNewFrames == NULL) {
4231 drmp3__free_from_callbacks(pFrames, &pMP3->allocationCallbacks);
4232 break;
4233 }
4234
4235 pFrames = pNewFrames;
4236 framesCapacity = newFramesCap;
4237 }
4238
4239 DRMP3_COPY_MEMORY(pFrames + totalFramesRead*pMP3->channels, temp, (size_t)(framesJustRead*pMP3->channels*sizeof(float)));
4240 totalFramesRead += framesJustRead;
4241
4242 /* If the number of frames we asked for is less that what we actually read it means we've reached the end. */
4243 if (framesJustRead != framesToReadRightNow) {
4244 break;
4245 }
4246 }
4247
4248 if (pConfig != NULL) {
4249 pConfig->channels = pMP3->channels;
4250 pConfig->sampleRate = pMP3->sampleRate;
4251 }
4252
4253 drmp3_uninit(pMP3);
4254
4255 if (pTotalFrameCount) {
4256 *pTotalFrameCount = totalFramesRead;
4257 }
4258
4259 return pFrames;
4260}
4261
4262static drmp3_int16* drmp3__full_read_and_close_s16(drmp3* pMP3, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount)
4263{
4264 drmp3_uint64 totalFramesRead = 0;
4265 drmp3_uint64 framesCapacity = 0;
4266 drmp3_int16* pFrames = NULL;
4267 drmp3_int16 temp[4096];
4268
4269 DRMP3_ASSERT(pMP3 != NULL);
4270
4271 for (;;) {
4272 drmp3_uint64 framesToReadRightNow = DRMP3_COUNTOF(temp) / pMP3->channels;
4273 drmp3_uint64 framesJustRead = drmp3_read_pcm_frames_s16(pMP3, framesToReadRightNow, temp);
4274 if (framesJustRead == 0) {
4275 break;
4276 }
4277
4278 /* Reallocate the output buffer if there's not enough room. */
4279 if (framesCapacity < totalFramesRead + framesJustRead) {
4280 drmp3_uint64 newFramesBufferSize;
4281 drmp3_uint64 oldFramesBufferSize;
4282 drmp3_uint64 newFramesCap;
4283 drmp3_int16* pNewFrames;
4284
4285 newFramesCap = framesCapacity * 2;
4286 if (newFramesCap < totalFramesRead + framesJustRead) {
4287 newFramesCap = totalFramesRead + framesJustRead;
4288 }
4289
4290 oldFramesBufferSize = framesCapacity * pMP3->channels * sizeof(drmp3_int16);
4291 newFramesBufferSize = newFramesCap * pMP3->channels * sizeof(drmp3_int16);
4292 if (newFramesBufferSize > (drmp3_uint64)DRMP3_SIZE_MAX) {
4293 break;
4294 }
4295
4296 pNewFrames = (drmp3_int16*)drmp3__realloc_from_callbacks(pFrames, (size_t)newFramesBufferSize, (size_t)oldFramesBufferSize, &pMP3->allocationCallbacks);
4297 if (pNewFrames == NULL) {
4298 drmp3__free_from_callbacks(pFrames, &pMP3->allocationCallbacks);
4299 break;
4300 }
4301
4302 pFrames = pNewFrames;
4303 framesCapacity = newFramesCap;
4304 }
4305
4306 DRMP3_COPY_MEMORY(pFrames + totalFramesRead*pMP3->channels, temp, (size_t)(framesJustRead*pMP3->channels*sizeof(drmp3_int16)));
4307 totalFramesRead += framesJustRead;
4308
4309 /* If the number of frames we asked for is less that what we actually read it means we've reached the end. */
4310 if (framesJustRead != framesToReadRightNow) {
4311 break;
4312 }
4313 }
4314
4315 if (pConfig != NULL) {
4316 pConfig->channels = pMP3->channels;
4317 pConfig->sampleRate = pMP3->sampleRate;
4318 }
4319
4320 drmp3_uninit(pMP3);
4321
4322 if (pTotalFrameCount) {
4323 *pTotalFrameCount = totalFramesRead;
4324 }
4325
4326 return pFrames;
4327}
4328
4329
4330DRMP3_API float* drmp3_open_and_read_pcm_frames_f32(drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks)
4331{
4332 drmp3 mp3;
4333 if (!drmp3_init(&mp3, onRead, onSeek, pUserData, pAllocationCallbacks)) {
4334 return NULL;
4335 }
4336
4337 return drmp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount);
4338}
4339
4340DRMP3_API drmp3_int16* drmp3_open_and_read_pcm_frames_s16(drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks)
4341{
4342 drmp3 mp3;
4343 if (!drmp3_init(&mp3, onRead, onSeek, pUserData, pAllocationCallbacks)) {
4344 return NULL;
4345 }
4346
4347 return drmp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount);
4348}
4349
4350
4351DRMP3_API float* drmp3_open_memory_and_read_pcm_frames_f32(const void* pData, size_t dataSize, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks)
4352{
4353 drmp3 mp3;
4354 if (!drmp3_init_memory(&mp3, pData, dataSize, pAllocationCallbacks)) {
4355 return NULL;
4356 }
4357
4358 return drmp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount);
4359}
4360
4361DRMP3_API drmp3_int16* drmp3_open_memory_and_read_pcm_frames_s16(const void* pData, size_t dataSize, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks)
4362{
4363 drmp3 mp3;
4364 if (!drmp3_init_memory(&mp3, pData, dataSize, pAllocationCallbacks)) {
4365 return NULL;
4366 }
4367
4368 return drmp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount);
4369}
4370
4371
4372#ifndef DR_MP3_NO_STDIO
4373DRMP3_API float* drmp3_open_file_and_read_pcm_frames_f32(const char* filePath, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks)
4374{
4375 drmp3 mp3;
4376 if (!drmp3_init_file(&mp3, filePath, pAllocationCallbacks)) {
4377 return NULL;
4378 }
4379
4380 return drmp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount);
4381}
4382
4383DRMP3_API drmp3_int16* drmp3_open_file_and_read_pcm_frames_s16(const char* filePath, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount, const drmp3_allocation_callbacks* pAllocationCallbacks)
4384{
4385 drmp3 mp3;
4386 if (!drmp3_init_file(&mp3, filePath, pAllocationCallbacks)) {
4387 return NULL;
4388 }
4389
4390 return drmp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount);
4391}
4392#endif
4393
4394DRMP3_API void* drmp3_malloc(size_t sz, const drmp3_allocation_callbacks* pAllocationCallbacks)
4395{
4396 if (pAllocationCallbacks != NULL) {
4397 return drmp3__malloc_from_callbacks(sz, pAllocationCallbacks);
4398 } else {
4399 return drmp3__malloc_default(sz, NULL);
4400 }
4401}
4402
4403DRMP3_API void drmp3_free(void* p, const drmp3_allocation_callbacks* pAllocationCallbacks)
4404{
4405 if (pAllocationCallbacks != NULL) {
4406 drmp3__free_from_callbacks(p, pAllocationCallbacks);
4407 } else {
4408 drmp3__free_default(p, NULL);
4409 }
4410}
4411
4412#endif /* dr_mp3_c */
4413#endif /*DR_MP3_IMPLEMENTATION*/
4414
4415/*
4416DIFFERENCES BETWEEN minimp3 AND dr_mp3
4417======================================
4418- First, keep in mind that minimp3 (https://github.com/lieff/minimp3) is where all the real work was done. All of the
4419 code relating to the actual decoding remains mostly unmodified, apart from some namespacing changes.
4420- dr_mp3 adds a pulling style API which allows you to deliver raw data via callbacks. So, rather than pushing data
4421 to the decoder, the decoder _pulls_ data from your callbacks.
4422- In addition to callbacks, a decoder can be initialized from a block of memory and a file.
4423- The dr_mp3 pull API reads PCM frames rather than whole MP3 frames.
4424- dr_mp3 adds convenience APIs for opening and decoding entire files in one go.
4425- dr_mp3 is fully namespaced, including the implementation section, which is more suitable when compiling projects
4426 as a single translation unit (aka unity builds). At the time of writing this, a unity build is not possible when
4427 using minimp3 in conjunction with stb_vorbis. dr_mp3 addresses this.
4428*/
4429
4430/*
4431RELEASE NOTES - v0.5.0
4432=======================
4433Version 0.5.0 has breaking API changes.
4434
4435Improved Client-Defined Memory Allocation
4436-----------------------------------------
4437The main change with this release is the addition of a more flexible way of implementing custom memory allocation routines. The
4438existing system of DRMP3_MALLOC, DRMP3_REALLOC and DRMP3_FREE are still in place and will be used by default when no custom
4439allocation callbacks are specified.
4440
4441To use the new system, you pass in a pointer to a drmp3_allocation_callbacks object to drmp3_init() and family, like this:
4442
4443 void* my_malloc(size_t sz, void* pUserData)
4444 {
4445 return malloc(sz);
4446 }
4447 void* my_realloc(void* p, size_t sz, void* pUserData)
4448 {
4449 return realloc(p, sz);
4450 }
4451 void my_free(void* p, void* pUserData)
4452 {
4453 free(p);
4454 }
4455
4456 ...
4457
4458 drmp3_allocation_callbacks allocationCallbacks;
4459 allocationCallbacks.pUserData = &myData;
4460 allocationCallbacks.onMalloc = my_malloc;
4461 allocationCallbacks.onRealloc = my_realloc;
4462 allocationCallbacks.onFree = my_free;
4463 drmp3_init_file(&mp3, "my_file.mp3", NULL, &allocationCallbacks);
4464
4465The advantage of this new system is that it allows you to specify user data which will be passed in to the allocation routines.
4466
4467Passing in null for the allocation callbacks object will cause dr_mp3 to use defaults which is the same as DRMP3_MALLOC,
4468DRMP3_REALLOC and DRMP3_FREE and the equivalent of how it worked in previous versions.
4469
4470Every API that opens a drmp3 object now takes this extra parameter. These include the following:
4471
4472 drmp3_init()
4473 drmp3_init_file()
4474 drmp3_init_memory()
4475 drmp3_open_and_read_pcm_frames_f32()
4476 drmp3_open_and_read_pcm_frames_s16()
4477 drmp3_open_memory_and_read_pcm_frames_f32()
4478 drmp3_open_memory_and_read_pcm_frames_s16()
4479 drmp3_open_file_and_read_pcm_frames_f32()
4480 drmp3_open_file_and_read_pcm_frames_s16()
4481
4482Renamed APIs
4483------------
4484The following APIs have been renamed for consistency with other dr_* libraries and to make it clear that they return PCM frame
4485counts rather than sample counts.
4486
4487 drmp3_open_and_read_f32() -> drmp3_open_and_read_pcm_frames_f32()
4488 drmp3_open_and_read_s16() -> drmp3_open_and_read_pcm_frames_s16()
4489 drmp3_open_memory_and_read_f32() -> drmp3_open_memory_and_read_pcm_frames_f32()
4490 drmp3_open_memory_and_read_s16() -> drmp3_open_memory_and_read_pcm_frames_s16()
4491 drmp3_open_file_and_read_f32() -> drmp3_open_file_and_read_pcm_frames_f32()
4492 drmp3_open_file_and_read_s16() -> drmp3_open_file_and_read_pcm_frames_s16()
4493*/
4494
4495/*
4496REVISION HISTORY
4497================
4498v0.6.39 - 2024-02-27
4499 - Fix a Wdouble-promotion warning.
4500
4501v0.6.38 - 2023-11-02
4502 - Fix build for ARMv6-M.
4503
4504v0.6.37 - 2023-07-07
4505 - Silence a static analysis warning.
4506
4507v0.6.36 - 2023-06-17
4508 - Fix an incorrect date in revision history. No functional change.
4509
4510v0.6.35 - 2023-05-22
4511 - Minor code restructure. No functional change.
4512
4513v0.6.34 - 2022-09-17
4514 - Fix compilation with DJGPP.
4515 - Fix compilation when compiling with x86 with no SSE2.
4516 - Remove an unnecessary variable from the drmp3 structure.
4517
4518v0.6.33 - 2022-04-10
4519 - Fix compilation error with the MSVC ARM64 build.
4520 - Fix compilation error on older versions of GCC.
4521 - Remove some unused functions.
4522
4523v0.6.32 - 2021-12-11
4524 - Fix a warning with Clang.
4525
4526v0.6.31 - 2021-08-22
4527 - Fix a bug when loading from memory.
4528
4529v0.6.30 - 2021-08-16
4530 - Silence some warnings.
4531 - Replace memory operations with DRMP3_* macros.
4532
4533v0.6.29 - 2021-08-08
4534 - Bring up to date with minimp3.
4535
4536v0.6.28 - 2021-07-31
4537 - Fix platform detection for ARM64.
4538 - Fix a compilation error with C89.
4539
4540v0.6.27 - 2021-02-21
4541 - Fix a warning due to referencing _MSC_VER when it is undefined.
4542
4543v0.6.26 - 2021-01-31
4544 - Bring up to date with minimp3.
4545
4546v0.6.25 - 2020-12-26
4547 - Remove DRMP3_DEFAULT_CHANNELS and DRMP3_DEFAULT_SAMPLE_RATE which are leftovers from some removed APIs.
4548
4549v0.6.24 - 2020-12-07
4550 - Fix a typo in version date for 0.6.23.
4551
4552v0.6.23 - 2020-12-03
4553 - Fix an error where a file can be closed twice when initialization of the decoder fails.
4554
4555v0.6.22 - 2020-12-02
4556 - Fix an error where it's possible for a file handle to be left open when initialization of the decoder fails.
4557
4558v0.6.21 - 2020-11-28
4559 - Bring up to date with minimp3.
4560
4561v0.6.20 - 2020-11-21
4562 - Fix compilation with OpenWatcom.
4563
4564v0.6.19 - 2020-11-13
4565 - Minor code clean up.
4566
4567v0.6.18 - 2020-11-01
4568 - Improve compiler support for older versions of GCC.
4569
4570v0.6.17 - 2020-09-28
4571 - Bring up to date with minimp3.
4572
4573v0.6.16 - 2020-08-02
4574 - Simplify sized types.
4575
4576v0.6.15 - 2020-07-25
4577 - Fix a compilation warning.
4578
4579v0.6.14 - 2020-07-23
4580 - Fix undefined behaviour with memmove().
4581
4582v0.6.13 - 2020-07-06
4583 - Fix a bug when converting from s16 to f32 in drmp3_read_pcm_frames_f32().
4584
4585v0.6.12 - 2020-06-23
4586 - Add include guard for the implementation section.
4587
4588v0.6.11 - 2020-05-26
4589 - Fix use of uninitialized variable error.
4590
4591v0.6.10 - 2020-05-16
4592 - Add compile-time and run-time version querying.
4593 - DRMP3_VERSION_MINOR
4594 - DRMP3_VERSION_MAJOR
4595 - DRMP3_VERSION_REVISION
4596 - DRMP3_VERSION_STRING
4597 - drmp3_version()
4598 - drmp3_version_string()
4599
4600v0.6.9 - 2020-04-30
4601 - Change the `pcm` parameter of drmp3dec_decode_frame() to a `const drmp3_uint8*` for consistency with internal APIs.
4602
4603v0.6.8 - 2020-04-26
4604 - Optimizations to decoding when initializing from memory.
4605
4606v0.6.7 - 2020-04-25
4607 - Fix a compilation error with DR_MP3_NO_STDIO
4608 - Optimization to decoding by reducing some data movement.
4609
4610v0.6.6 - 2020-04-23
4611 - Fix a minor bug with the running PCM frame counter.
4612
4613v0.6.5 - 2020-04-19
4614 - Fix compilation error on ARM builds.
4615
4616v0.6.4 - 2020-04-19
4617 - Bring up to date with changes to minimp3.
4618
4619v0.6.3 - 2020-04-13
4620 - Fix some pedantic warnings.
4621
4622v0.6.2 - 2020-04-10
4623 - Fix a crash in drmp3_open_*_and_read_pcm_frames_*() if the output config object is NULL.
4624
4625v0.6.1 - 2020-04-05
4626 - Fix warnings.
4627
4628v0.6.0 - 2020-04-04
4629 - API CHANGE: Remove the pConfig parameter from the following APIs:
4630 - drmp3_init()
4631 - drmp3_init_memory()
4632 - drmp3_init_file()
4633 - Add drmp3_init_file_w() for opening a file from a wchar_t encoded path.
4634
4635v0.5.6 - 2020-02-12
4636 - Bring up to date with minimp3.
4637
4638v0.5.5 - 2020-01-29
4639 - Fix a memory allocation bug in high level s16 decoding APIs.
4640
4641v0.5.4 - 2019-12-02
4642 - Fix a possible null pointer dereference when using custom memory allocators for realloc().
4643
4644v0.5.3 - 2019-11-14
4645 - Fix typos in documentation.
4646
4647v0.5.2 - 2019-11-02
4648 - Bring up to date with minimp3.
4649
4650v0.5.1 - 2019-10-08
4651 - Fix a warning with GCC.
4652
4653v0.5.0 - 2019-10-07
4654 - API CHANGE: Add support for user defined memory allocation routines. This system allows the program to specify their own memory allocation
4655 routines with a user data pointer for client-specific contextual data. This adds an extra parameter to the end of the following APIs:
4656 - drmp3_init()
4657 - drmp3_init_file()
4658 - drmp3_init_memory()
4659 - drmp3_open_and_read_pcm_frames_f32()
4660 - drmp3_open_and_read_pcm_frames_s16()
4661 - drmp3_open_memory_and_read_pcm_frames_f32()
4662 - drmp3_open_memory_and_read_pcm_frames_s16()
4663 - drmp3_open_file_and_read_pcm_frames_f32()
4664 - drmp3_open_file_and_read_pcm_frames_s16()
4665 - API CHANGE: Renamed the following APIs:
4666 - drmp3_open_and_read_f32() -> drmp3_open_and_read_pcm_frames_f32()
4667 - drmp3_open_and_read_s16() -> drmp3_open_and_read_pcm_frames_s16()
4668 - drmp3_open_memory_and_read_f32() -> drmp3_open_memory_and_read_pcm_frames_f32()
4669 - drmp3_open_memory_and_read_s16() -> drmp3_open_memory_and_read_pcm_frames_s16()
4670 - drmp3_open_file_and_read_f32() -> drmp3_open_file_and_read_pcm_frames_f32()
4671 - drmp3_open_file_and_read_s16() -> drmp3_open_file_and_read_pcm_frames_s16()
4672
4673v0.4.7 - 2019-07-28
4674 - Fix a compiler error.
4675
4676v0.4.6 - 2019-06-14
4677 - Fix a compiler error.
4678
4679v0.4.5 - 2019-06-06
4680 - Bring up to date with minimp3.
4681
4682v0.4.4 - 2019-05-06
4683 - Fixes to the VC6 build.
4684
4685v0.4.3 - 2019-05-05
4686 - Use the channel count and/or sample rate of the first MP3 frame instead of DRMP3_DEFAULT_CHANNELS and
4687 DRMP3_DEFAULT_SAMPLE_RATE when they are set to 0. To use the old behaviour, just set the relevant property to
4688 DRMP3_DEFAULT_CHANNELS or DRMP3_DEFAULT_SAMPLE_RATE.
4689 - Add s16 reading APIs
4690 - drmp3_read_pcm_frames_s16
4691 - drmp3_open_memory_and_read_pcm_frames_s16
4692 - drmp3_open_and_read_pcm_frames_s16
4693 - drmp3_open_file_and_read_pcm_frames_s16
4694 - Add drmp3_get_mp3_and_pcm_frame_count() to the public header section.
4695 - Add support for C89.
4696 - Change license to choice of public domain or MIT-0.
4697
4698v0.4.2 - 2019-02-21
4699 - Fix a warning.
4700
4701v0.4.1 - 2018-12-30
4702 - Fix a warning.
4703
4704v0.4.0 - 2018-12-16
4705 - API CHANGE: Rename some APIs:
4706 - drmp3_read_f32 -> to drmp3_read_pcm_frames_f32
4707 - drmp3_seek_to_frame -> drmp3_seek_to_pcm_frame
4708 - drmp3_open_and_decode_f32 -> drmp3_open_and_read_pcm_frames_f32
4709 - drmp3_open_and_decode_memory_f32 -> drmp3_open_memory_and_read_pcm_frames_f32
4710 - drmp3_open_and_decode_file_f32 -> drmp3_open_file_and_read_pcm_frames_f32
4711 - Add drmp3_get_pcm_frame_count().
4712 - Add drmp3_get_mp3_frame_count().
4713 - Improve seeking performance.
4714
4715v0.3.2 - 2018-09-11
4716 - Fix a couple of memory leaks.
4717 - Bring up to date with minimp3.
4718
4719v0.3.1 - 2018-08-25
4720 - Fix C++ build.
4721
4722v0.3.0 - 2018-08-25
4723 - Bring up to date with minimp3. This has a minor API change: the "pcm" parameter of drmp3dec_decode_frame() has
4724 been changed from short* to void* because it can now output both s16 and f32 samples, depending on whether or
4725 not the DR_MP3_FLOAT_OUTPUT option is set.
4726
4727v0.2.11 - 2018-08-08
4728 - Fix a bug where the last part of a file is not read.
4729
4730v0.2.10 - 2018-08-07
4731 - Improve 64-bit detection.
4732
4733v0.2.9 - 2018-08-05
4734 - Fix C++ build on older versions of GCC.
4735 - Bring up to date with minimp3.
4736
4737v0.2.8 - 2018-08-02
4738 - Fix compilation errors with older versions of GCC.
4739
4740v0.2.7 - 2018-07-13
4741 - Bring up to date with minimp3.
4742
4743v0.2.6 - 2018-07-12
4744 - Bring up to date with minimp3.
4745
4746v0.2.5 - 2018-06-22
4747 - Bring up to date with minimp3.
4748
4749v0.2.4 - 2018-05-12
4750 - Bring up to date with minimp3.
4751
4752v0.2.3 - 2018-04-29
4753 - Fix TCC build.
4754
4755v0.2.2 - 2018-04-28
4756 - Fix bug when opening a decoder from memory.
4757
4758v0.2.1 - 2018-04-27
4759 - Efficiency improvements when the decoder reaches the end of the stream.
4760
4761v0.2 - 2018-04-21
4762 - Bring up to date with minimp3.
4763 - Start using major.minor.revision versioning.
4764
4765v0.1d - 2018-03-30
4766 - Bring up to date with minimp3.
4767
4768v0.1c - 2018-03-11
4769 - Fix C++ build error.
4770
4771v0.1b - 2018-03-07
4772 - Bring up to date with minimp3.
4773
4774v0.1a - 2018-02-28
4775 - Fix compilation error on GCC/Clang.
4776 - Fix some warnings.
4777
4778v0.1 - 2018-02-xx
4779 - Initial versioned release.
4780*/
4781
4782/*
4783This software is available as a choice of the following licenses. Choose
4784whichever you prefer.
4785
4786===============================================================================
4787ALTERNATIVE 1 - Public Domain (www.unlicense.org)
4788===============================================================================
4789This is free and unencumbered software released into the public domain.
4790
4791Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
4792software, either in source code form or as a compiled binary, for any purpose,
4793commercial or non-commercial, and by any means.
4794
4795In jurisdictions that recognize copyright laws, the author or authors of this
4796software dedicate any and all copyright interest in the software to the public
4797domain. We make this dedication for the benefit of the public at large and to
4798the detriment of our heirs and successors. We intend this dedication to be an
4799overt act of relinquishment in perpetuity of all present and future rights to
4800this software under copyright law.
4801
4802THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4803IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4804FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
4805AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
4806ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
4807WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4808
4809For more information, please refer to <http://unlicense.org/>
4810
4811===============================================================================
4812ALTERNATIVE 2 - MIT No Attribution
4813===============================================================================
4814Copyright 2023 David Reid
4815
4816Permission is hereby granted, free of charge, to any person obtaining a copy of
4817this software and associated documentation files (the "Software"), to deal in
4818the Software without restriction, including without limitation the rights to
4819use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
4820of the Software, and to permit persons to whom the Software is furnished to do
4821so.
4822
4823THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4824IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4825FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
4826AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
4827LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
4828OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
4829SOFTWARE.
4830*/
4831
4832/*
4833 https://github.com/lieff/minimp3
4834 To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide.
4835 This software is distributed without any warranty.
4836 See <http://creativecommons.org/publicdomain/zero/1.0/>.
4837*/
diff --git a/raylib/src/external/dr_wav.h b/raylib/src/external/dr_wav.h
new file mode 100644
index 0000000..a8207ab
--- /dev/null
+++ b/raylib/src/external/dr_wav.h
@@ -0,0 +1,8815 @@
1/*
2WAV audio loader and writer. Choice of public domain or MIT-0. See license statements at the end of this file.
3dr_wav - v0.13.16 - 2024-02-27
4
5David Reid - mackron@gmail.com
6
7GitHub: https://github.com/mackron/dr_libs
8*/
9
10/*
11Introduction
12============
13This is a single file library. To use it, do something like the following in one .c file.
14
15 ```c
16 #define DR_WAV_IMPLEMENTATION
17 #include "dr_wav.h"
18 ```
19
20You can then #include this file in other parts of the program as you would with any other header file. Do something like the following to read audio data:
21
22 ```c
23 drwav wav;
24 if (!drwav_init_file(&wav, "my_song.wav", NULL)) {
25 // Error opening WAV file.
26 }
27
28 drwav_int32* pDecodedInterleavedPCMFrames = malloc(wav.totalPCMFrameCount * wav.channels * sizeof(drwav_int32));
29 size_t numberOfSamplesActuallyDecoded = drwav_read_pcm_frames_s32(&wav, wav.totalPCMFrameCount, pDecodedInterleavedPCMFrames);
30
31 ...
32
33 drwav_uninit(&wav);
34 ```
35
36If you just want to quickly open and read the audio data in a single operation you can do something like this:
37
38 ```c
39 unsigned int channels;
40 unsigned int sampleRate;
41 drwav_uint64 totalPCMFrameCount;
42 float* pSampleData = drwav_open_file_and_read_pcm_frames_f32("my_song.wav", &channels, &sampleRate, &totalPCMFrameCount, NULL);
43 if (pSampleData == NULL) {
44 // Error opening and reading WAV file.
45 }
46
47 ...
48
49 drwav_free(pSampleData, NULL);
50 ```
51
52The examples above use versions of the API that convert the audio data to a consistent format (32-bit signed PCM, in this case), but you can still output the
53audio data in its internal format (see notes below for supported formats):
54
55 ```c
56 size_t framesRead = drwav_read_pcm_frames(&wav, wav.totalPCMFrameCount, pDecodedInterleavedPCMFrames);
57 ```
58
59You can also read the raw bytes of audio data, which could be useful if dr_wav does not have native support for a particular data format:
60
61 ```c
62 size_t bytesRead = drwav_read_raw(&wav, bytesToRead, pRawDataBuffer);
63 ```
64
65dr_wav can also be used to output WAV files. This does not currently support compressed formats. To use this, look at `drwav_init_write()`,
66`drwav_init_file_write()`, etc. Use `drwav_write_pcm_frames()` to write samples, or `drwav_write_raw()` to write raw data in the "data" chunk.
67
68 ```c
69 drwav_data_format format;
70 format.container = drwav_container_riff; // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64.
71 format.format = DR_WAVE_FORMAT_PCM; // <-- Any of the DR_WAVE_FORMAT_* codes.
72 format.channels = 2;
73 format.sampleRate = 44100;
74 format.bitsPerSample = 16;
75 drwav_init_file_write(&wav, "data/recording.wav", &format, NULL);
76
77 ...
78
79 drwav_uint64 framesWritten = drwav_write_pcm_frames(pWav, frameCount, pSamples);
80 ```
81
82Note that writing to AIFF or RIFX is not supported.
83
84dr_wav has support for decoding from a number of different encapsulation formats. See below for details.
85
86
87Build Options
88=============
89#define these options before including this file.
90
91#define DR_WAV_NO_CONVERSION_API
92 Disables conversion APIs such as `drwav_read_pcm_frames_f32()` and `drwav_s16_to_f32()`.
93
94#define DR_WAV_NO_STDIO
95 Disables APIs that initialize a decoder from a file such as `drwav_init_file()`, `drwav_init_file_write()`, etc.
96
97#define DR_WAV_NO_WCHAR
98 Disables all functions ending with `_w`. Use this if your compiler does not provide wchar.h. Not required if DR_WAV_NO_STDIO is also defined.
99
100
101Supported Encapsulations
102========================
103- RIFF (Regular WAV)
104- RIFX (Big-Endian)
105- AIFF (Does not currently support ADPCM)
106- RF64
107- W64
108
109Note that AIFF and RIFX do not support write mode, nor do they support reading of metadata.
110
111
112Supported Encodings
113===================
114- Unsigned 8-bit PCM
115- Signed 12-bit PCM
116- Signed 16-bit PCM
117- Signed 24-bit PCM
118- Signed 32-bit PCM
119- IEEE 32-bit floating point
120- IEEE 64-bit floating point
121- A-law and u-law
122- Microsoft ADPCM
123- IMA ADPCM (DVI, format code 0x11)
124
1258-bit PCM encodings are always assumed to be unsigned. Signed 8-bit encoding can only be read with `drwav_read_raw()`.
126
127Note that ADPCM is not currently supported with AIFF. Contributions welcome.
128
129
130Notes
131=====
132- Samples are always interleaved.
133- The default read function does not do any data conversion. Use `drwav_read_pcm_frames_f32()`, `drwav_read_pcm_frames_s32()` and `drwav_read_pcm_frames_s16()`
134 to read and convert audio data to 32-bit floating point, signed 32-bit integer and signed 16-bit integer samples respectively.
135- dr_wav will try to read the WAV file as best it can, even if it's not strictly conformant to the WAV format.
136*/
137
138#ifndef dr_wav_h
139#define dr_wav_h
140
141#ifdef __cplusplus
142extern "C" {
143#endif
144
145#define DRWAV_STRINGIFY(x) #x
146#define DRWAV_XSTRINGIFY(x) DRWAV_STRINGIFY(x)
147
148#define DRWAV_VERSION_MAJOR 0
149#define DRWAV_VERSION_MINOR 13
150#define DRWAV_VERSION_REVISION 16
151#define DRWAV_VERSION_STRING DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION)
152
153#include <stddef.h> /* For size_t. */
154
155/* Sized Types */
156typedef signed char drwav_int8;
157typedef unsigned char drwav_uint8;
158typedef signed short drwav_int16;
159typedef unsigned short drwav_uint16;
160typedef signed int drwav_int32;
161typedef unsigned int drwav_uint32;
162#if defined(_MSC_VER) && !defined(__clang__)
163 typedef signed __int64 drwav_int64;
164 typedef unsigned __int64 drwav_uint64;
165#else
166 #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
167 #pragma GCC diagnostic push
168 #pragma GCC diagnostic ignored "-Wlong-long"
169 #if defined(__clang__)
170 #pragma GCC diagnostic ignored "-Wc++11-long-long"
171 #endif
172 #endif
173 typedef signed long long drwav_int64;
174 typedef unsigned long long drwav_uint64;
175 #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
176 #pragma GCC diagnostic pop
177 #endif
178#endif
179#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__)
180 typedef drwav_uint64 drwav_uintptr;
181#else
182 typedef drwav_uint32 drwav_uintptr;
183#endif
184typedef drwav_uint8 drwav_bool8;
185typedef drwav_uint32 drwav_bool32;
186#define DRWAV_TRUE 1
187#define DRWAV_FALSE 0
188/* End Sized Types */
189
190/* Decorations */
191#if !defined(DRWAV_API)
192 #if defined(DRWAV_DLL)
193 #if defined(_WIN32)
194 #define DRWAV_DLL_IMPORT __declspec(dllimport)
195 #define DRWAV_DLL_EXPORT __declspec(dllexport)
196 #define DRWAV_DLL_PRIVATE static
197 #else
198 #if defined(__GNUC__) && __GNUC__ >= 4
199 #define DRWAV_DLL_IMPORT __attribute__((visibility("default")))
200 #define DRWAV_DLL_EXPORT __attribute__((visibility("default")))
201 #define DRWAV_DLL_PRIVATE __attribute__((visibility("hidden")))
202 #else
203 #define DRWAV_DLL_IMPORT
204 #define DRWAV_DLL_EXPORT
205 #define DRWAV_DLL_PRIVATE static
206 #endif
207 #endif
208
209 #if defined(DR_WAV_IMPLEMENTATION) || defined(DRWAV_IMPLEMENTATION)
210 #define DRWAV_API DRWAV_DLL_EXPORT
211 #else
212 #define DRWAV_API DRWAV_DLL_IMPORT
213 #endif
214 #define DRWAV_PRIVATE DRWAV_DLL_PRIVATE
215 #else
216 #define DRWAV_API extern
217 #define DRWAV_PRIVATE static
218 #endif
219#endif
220/* End Decorations */
221
222/* Result Codes */
223typedef drwav_int32 drwav_result;
224#define DRWAV_SUCCESS 0
225#define DRWAV_ERROR -1 /* A generic error. */
226#define DRWAV_INVALID_ARGS -2
227#define DRWAV_INVALID_OPERATION -3
228#define DRWAV_OUT_OF_MEMORY -4
229#define DRWAV_OUT_OF_RANGE -5
230#define DRWAV_ACCESS_DENIED -6
231#define DRWAV_DOES_NOT_EXIST -7
232#define DRWAV_ALREADY_EXISTS -8
233#define DRWAV_TOO_MANY_OPEN_FILES -9
234#define DRWAV_INVALID_FILE -10
235#define DRWAV_TOO_BIG -11
236#define DRWAV_PATH_TOO_LONG -12
237#define DRWAV_NAME_TOO_LONG -13
238#define DRWAV_NOT_DIRECTORY -14
239#define DRWAV_IS_DIRECTORY -15
240#define DRWAV_DIRECTORY_NOT_EMPTY -16
241#define DRWAV_END_OF_FILE -17
242#define DRWAV_NO_SPACE -18
243#define DRWAV_BUSY -19
244#define DRWAV_IO_ERROR -20
245#define DRWAV_INTERRUPT -21
246#define DRWAV_UNAVAILABLE -22
247#define DRWAV_ALREADY_IN_USE -23
248#define DRWAV_BAD_ADDRESS -24
249#define DRWAV_BAD_SEEK -25
250#define DRWAV_BAD_PIPE -26
251#define DRWAV_DEADLOCK -27
252#define DRWAV_TOO_MANY_LINKS -28
253#define DRWAV_NOT_IMPLEMENTED -29
254#define DRWAV_NO_MESSAGE -30
255#define DRWAV_BAD_MESSAGE -31
256#define DRWAV_NO_DATA_AVAILABLE -32
257#define DRWAV_INVALID_DATA -33
258#define DRWAV_TIMEOUT -34
259#define DRWAV_NO_NETWORK -35
260#define DRWAV_NOT_UNIQUE -36
261#define DRWAV_NOT_SOCKET -37
262#define DRWAV_NO_ADDRESS -38
263#define DRWAV_BAD_PROTOCOL -39
264#define DRWAV_PROTOCOL_UNAVAILABLE -40
265#define DRWAV_PROTOCOL_NOT_SUPPORTED -41
266#define DRWAV_PROTOCOL_FAMILY_NOT_SUPPORTED -42
267#define DRWAV_ADDRESS_FAMILY_NOT_SUPPORTED -43
268#define DRWAV_SOCKET_NOT_SUPPORTED -44
269#define DRWAV_CONNECTION_RESET -45
270#define DRWAV_ALREADY_CONNECTED -46
271#define DRWAV_NOT_CONNECTED -47
272#define DRWAV_CONNECTION_REFUSED -48
273#define DRWAV_NO_HOST -49
274#define DRWAV_IN_PROGRESS -50
275#define DRWAV_CANCELLED -51
276#define DRWAV_MEMORY_ALREADY_MAPPED -52
277#define DRWAV_AT_END -53
278/* End Result Codes */
279
280/* Common data formats. */
281#define DR_WAVE_FORMAT_PCM 0x1
282#define DR_WAVE_FORMAT_ADPCM 0x2
283#define DR_WAVE_FORMAT_IEEE_FLOAT 0x3
284#define DR_WAVE_FORMAT_ALAW 0x6
285#define DR_WAVE_FORMAT_MULAW 0x7
286#define DR_WAVE_FORMAT_DVI_ADPCM 0x11
287#define DR_WAVE_FORMAT_EXTENSIBLE 0xFFFE
288
289/* Flags to pass into drwav_init_ex(), etc. */
290#define DRWAV_SEQUENTIAL 0x00000001
291#define DRWAV_WITH_METADATA 0x00000002
292
293DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision);
294DRWAV_API const char* drwav_version_string(void);
295
296/* Allocation Callbacks */
297typedef struct
298{
299 void* pUserData;
300 void* (* onMalloc)(size_t sz, void* pUserData);
301 void* (* onRealloc)(void* p, size_t sz, void* pUserData);
302 void (* onFree)(void* p, void* pUserData);
303} drwav_allocation_callbacks;
304/* End Allocation Callbacks */
305
306typedef enum
307{
308 drwav_seek_origin_start,
309 drwav_seek_origin_current
310} drwav_seek_origin;
311
312typedef enum
313{
314 drwav_container_riff,
315 drwav_container_rifx,
316 drwav_container_w64,
317 drwav_container_rf64,
318 drwav_container_aiff
319} drwav_container;
320
321typedef struct
322{
323 union
324 {
325 drwav_uint8 fourcc[4];
326 drwav_uint8 guid[16];
327 } id;
328
329 /* The size in bytes of the chunk. */
330 drwav_uint64 sizeInBytes;
331
332 /*
333 RIFF = 2 byte alignment.
334 W64 = 8 byte alignment.
335 */
336 unsigned int paddingSize;
337} drwav_chunk_header;
338
339typedef struct
340{
341 /*
342 The format tag exactly as specified in the wave file's "fmt" chunk. This can be used by applications
343 that require support for data formats not natively supported by dr_wav.
344 */
345 drwav_uint16 formatTag;
346
347 /* The number of channels making up the audio data. When this is set to 1 it is mono, 2 is stereo, etc. */
348 drwav_uint16 channels;
349
350 /* The sample rate. Usually set to something like 44100. */
351 drwav_uint32 sampleRate;
352
353 /* Average bytes per second. You probably don't need this, but it's left here for informational purposes. */
354 drwav_uint32 avgBytesPerSec;
355
356 /* Block align. This is equal to the number of channels * bytes per sample. */
357 drwav_uint16 blockAlign;
358
359 /* Bits per sample. */
360 drwav_uint16 bitsPerSample;
361
362 /* The size of the extended data. Only used internally for validation, but left here for informational purposes. */
363 drwav_uint16 extendedSize;
364
365 /*
366 The number of valid bits per sample. When <formatTag> is equal to WAVE_FORMAT_EXTENSIBLE, <bitsPerSample>
367 is always rounded up to the nearest multiple of 8. This variable contains information about exactly how
368 many bits are valid per sample. Mainly used for informational purposes.
369 */
370 drwav_uint16 validBitsPerSample;
371
372 /* The channel mask. Not used at the moment. */
373 drwav_uint32 channelMask;
374
375 /* The sub-format, exactly as specified by the wave file. */
376 drwav_uint8 subFormat[16];
377} drwav_fmt;
378
379DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT);
380
381
382/*
383Callback for when data is read. Return value is the number of bytes actually read.
384
385pUserData [in] The user data that was passed to drwav_init() and family.
386pBufferOut [out] The output buffer.
387bytesToRead [in] The number of bytes to read.
388
389Returns the number of bytes actually read.
390
391A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback until
392either the entire bytesToRead is filled or you have reached the end of the stream.
393*/
394typedef size_t (* drwav_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead);
395
396/*
397Callback for when data is written. Returns value is the number of bytes actually written.
398
399pUserData [in] The user data that was passed to drwav_init_write() and family.
400pData [out] A pointer to the data to write.
401bytesToWrite [in] The number of bytes to write.
402
403Returns the number of bytes actually written.
404
405If the return value differs from bytesToWrite, it indicates an error.
406*/
407typedef size_t (* drwav_write_proc)(void* pUserData, const void* pData, size_t bytesToWrite);
408
409/*
410Callback for when data needs to be seeked.
411
412pUserData [in] The user data that was passed to drwav_init() and family.
413offset [in] The number of bytes to move, relative to the origin. Will never be negative.
414origin [in] The origin of the seek - the current position or the start of the stream.
415
416Returns whether or not the seek was successful.
417
418Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which will be either drwav_seek_origin_start or
419drwav_seek_origin_current.
420*/
421typedef drwav_bool32 (* drwav_seek_proc)(void* pUserData, int offset, drwav_seek_origin origin);
422
423/*
424Callback for when drwav_init_ex() finds a chunk.
425
426pChunkUserData [in] The user data that was passed to the pChunkUserData parameter of drwav_init_ex() and family.
427onRead [in] A pointer to the function to call when reading.
428onSeek [in] A pointer to the function to call when seeking.
429pReadSeekUserData [in] The user data that was passed to the pReadSeekUserData parameter of drwav_init_ex() and family.
430pChunkHeader [in] A pointer to an object containing basic header information about the chunk. Use this to identify the chunk.
431container [in] Whether or not the WAV file is a RIFF or Wave64 container. If you're unsure of the difference, assume RIFF.
432pFMT [in] A pointer to the object containing the contents of the "fmt" chunk.
433
434Returns the number of bytes read + seeked.
435
436To read data from the chunk, call onRead(), passing in pReadSeekUserData as the first parameter. Do the same for seeking with onSeek(). The return value must
437be the total number of bytes you have read _plus_ seeked.
438
439Use the `container` argument to discriminate the fields in `pChunkHeader->id`. If the container is `drwav_container_riff` or `drwav_container_rf64` you should
440use `id.fourcc`, otherwise you should use `id.guid`.
441
442The `pFMT` parameter can be used to determine the data format of the wave file. Use `drwav_fmt_get_format()` to get the sample format, which will be one of the
443`DR_WAVE_FORMAT_*` identifiers.
444
445The read pointer will be sitting on the first byte after the chunk's header. You must not attempt to read beyond the boundary of the chunk.
446*/
447typedef drwav_uint64 (* drwav_chunk_proc)(void* pChunkUserData, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pReadSeekUserData, const drwav_chunk_header* pChunkHeader, drwav_container container, const drwav_fmt* pFMT);
448
449
450/* Structure for internal use. Only used for loaders opened with drwav_init_memory(). */
451typedef struct
452{
453 const drwav_uint8* data;
454 size_t dataSize;
455 size_t currentReadPos;
456} drwav__memory_stream;
457
458/* Structure for internal use. Only used for writers opened with drwav_init_memory_write(). */
459typedef struct
460{
461 void** ppData;
462 size_t* pDataSize;
463 size_t dataSize;
464 size_t dataCapacity;
465 size_t currentWritePos;
466} drwav__memory_stream_write;
467
468typedef struct
469{
470 drwav_container container; /* RIFF, W64. */
471 drwav_uint32 format; /* DR_WAVE_FORMAT_* */
472 drwav_uint32 channels;
473 drwav_uint32 sampleRate;
474 drwav_uint32 bitsPerSample;
475} drwav_data_format;
476
477typedef enum
478{
479 drwav_metadata_type_none = 0,
480
481 /*
482 Unknown simply means a chunk that drwav does not handle specifically. You can still ask to
483 receive these chunks as metadata objects. It is then up to you to interpret the chunk's data.
484 You can also write unknown metadata to a wav file. Be careful writing unknown chunks if you
485 have also edited the audio data. The unknown chunks could represent offsets/sizes that no
486 longer correctly correspond to the audio data.
487 */
488 drwav_metadata_type_unknown = 1 << 0,
489
490 /* Only 1 of each of these metadata items are allowed in a wav file. */
491 drwav_metadata_type_smpl = 1 << 1,
492 drwav_metadata_type_inst = 1 << 2,
493 drwav_metadata_type_cue = 1 << 3,
494 drwav_metadata_type_acid = 1 << 4,
495 drwav_metadata_type_bext = 1 << 5,
496
497 /*
498 Wav files often have a LIST chunk. This is a chunk that contains a set of subchunks. For this
499 higher-level metadata API, we don't make a distinction between a regular chunk and a LIST
500 subchunk. Instead, they are all just 'metadata' items.
501
502 There can be multiple of these metadata items in a wav file.
503 */
504 drwav_metadata_type_list_label = 1 << 6,
505 drwav_metadata_type_list_note = 1 << 7,
506 drwav_metadata_type_list_labelled_cue_region = 1 << 8,
507
508 drwav_metadata_type_list_info_software = 1 << 9,
509 drwav_metadata_type_list_info_copyright = 1 << 10,
510 drwav_metadata_type_list_info_title = 1 << 11,
511 drwav_metadata_type_list_info_artist = 1 << 12,
512 drwav_metadata_type_list_info_comment = 1 << 13,
513 drwav_metadata_type_list_info_date = 1 << 14,
514 drwav_metadata_type_list_info_genre = 1 << 15,
515 drwav_metadata_type_list_info_album = 1 << 16,
516 drwav_metadata_type_list_info_tracknumber = 1 << 17,
517
518 /* Other type constants for convenience. */
519 drwav_metadata_type_list_all_info_strings = drwav_metadata_type_list_info_software
520 | drwav_metadata_type_list_info_copyright
521 | drwav_metadata_type_list_info_title
522 | drwav_metadata_type_list_info_artist
523 | drwav_metadata_type_list_info_comment
524 | drwav_metadata_type_list_info_date
525 | drwav_metadata_type_list_info_genre
526 | drwav_metadata_type_list_info_album
527 | drwav_metadata_type_list_info_tracknumber,
528
529 drwav_metadata_type_list_all_adtl = drwav_metadata_type_list_label
530 | drwav_metadata_type_list_note
531 | drwav_metadata_type_list_labelled_cue_region,
532
533 drwav_metadata_type_all = -2, /*0xFFFFFFFF & ~drwav_metadata_type_unknown,*/
534 drwav_metadata_type_all_including_unknown = -1 /*0xFFFFFFFF,*/
535} drwav_metadata_type;
536
537/*
538Sampler Metadata
539
540The sampler chunk contains information about how a sound should be played in the context of a whole
541audio production, and when used in a sampler. See https://en.wikipedia.org/wiki/Sample-based_synthesis.
542*/
543typedef enum
544{
545 drwav_smpl_loop_type_forward = 0,
546 drwav_smpl_loop_type_pingpong = 1,
547 drwav_smpl_loop_type_backward = 2
548} drwav_smpl_loop_type;
549
550typedef struct
551{
552 /* The ID of the associated cue point, see drwav_cue and drwav_cue_point. As with all cue point IDs, this can correspond to a label chunk to give this loop a name, see drwav_list_label_or_note. */
553 drwav_uint32 cuePointId;
554
555 /* See drwav_smpl_loop_type. */
556 drwav_uint32 type;
557
558 /* The byte offset of the first sample to be played in the loop. */
559 drwav_uint32 firstSampleByteOffset;
560
561 /* The byte offset into the audio data of the last sample to be played in the loop. */
562 drwav_uint32 lastSampleByteOffset;
563
564 /* A value to represent that playback should occur at a point between samples. This value ranges from 0 to UINT32_MAX. Where a value of 0 means no fraction, and a value of (UINT32_MAX / 2) would mean half a sample. */
565 drwav_uint32 sampleFraction;
566
567 /* Number of times to play the loop. 0 means loop infinitely. */
568 drwav_uint32 playCount;
569} drwav_smpl_loop;
570
571typedef struct
572{
573 /* IDs for a particular MIDI manufacturer. 0 if not used. */
574 drwav_uint32 manufacturerId;
575 drwav_uint32 productId;
576
577 /* The period of 1 sample in nanoseconds. */
578 drwav_uint32 samplePeriodNanoseconds;
579
580 /* The MIDI root note of this file. 0 to 127. */
581 drwav_uint32 midiUnityNote;
582
583 /* The fraction of a semitone up from the given MIDI note. This is a value from 0 to UINT32_MAX, where 0 means no change and (UINT32_MAX / 2) is half a semitone (AKA 50 cents). */
584 drwav_uint32 midiPitchFraction;
585
586 /* Data relating to SMPTE standards which are used for syncing audio and video. 0 if not used. */
587 drwav_uint32 smpteFormat;
588 drwav_uint32 smpteOffset;
589
590 /* drwav_smpl_loop loops. */
591 drwav_uint32 sampleLoopCount;
592
593 /* Optional sampler-specific data. */
594 drwav_uint32 samplerSpecificDataSizeInBytes;
595
596 drwav_smpl_loop* pLoops;
597 drwav_uint8* pSamplerSpecificData;
598} drwav_smpl;
599
600/*
601Instrument Metadata
602
603The inst metadata contains data about how a sound should be played as part of an instrument. This
604commonly read by samplers. See https://en.wikipedia.org/wiki/Sample-based_synthesis.
605*/
606typedef struct
607{
608 drwav_int8 midiUnityNote; /* The root note of the audio as a MIDI note number. 0 to 127. */
609 drwav_int8 fineTuneCents; /* -50 to +50 */
610 drwav_int8 gainDecibels; /* -64 to +64 */
611 drwav_int8 lowNote; /* 0 to 127 */
612 drwav_int8 highNote; /* 0 to 127 */
613 drwav_int8 lowVelocity; /* 1 to 127 */
614 drwav_int8 highVelocity; /* 1 to 127 */
615} drwav_inst;
616
617/*
618Cue Metadata
619
620Cue points are markers at specific points in the audio. They often come with an associated piece of
621drwav_list_label_or_note metadata which contains the text for the marker.
622*/
623typedef struct
624{
625 /* Unique identification value. */
626 drwav_uint32 id;
627
628 /* Set to 0. This is only relevant if there is a 'playlist' chunk - which is not supported by dr_wav. */
629 drwav_uint32 playOrderPosition;
630
631 /* Should always be "data". This represents the fourcc value of the chunk that this cue point corresponds to. dr_wav only supports a single data chunk so this should always be "data". */
632 drwav_uint8 dataChunkId[4];
633
634 /* Set to 0. This is only relevant if there is a wave list chunk. dr_wav, like lots of readers/writers, do not support this. */
635 drwav_uint32 chunkStart;
636
637 /* Set to 0 for uncompressed formats. Else the last byte in compressed wave data where decompression can begin to find the value of the corresponding sample value. */
638 drwav_uint32 blockStart;
639
640 /* For uncompressed formats this is the byte offset of the cue point into the audio data. For compressed formats this is relative to the block specified with blockStart. */
641 drwav_uint32 sampleByteOffset;
642} drwav_cue_point;
643
644typedef struct
645{
646 drwav_uint32 cuePointCount;
647 drwav_cue_point *pCuePoints;
648} drwav_cue;
649
650/*
651Acid Metadata
652
653This chunk contains some information about the time signature and the tempo of the audio.
654*/
655typedef enum
656{
657 drwav_acid_flag_one_shot = 1, /* If this is not set, then it is a loop instead of a one-shot. */
658 drwav_acid_flag_root_note_set = 2,
659 drwav_acid_flag_stretch = 4,
660 drwav_acid_flag_disk_based = 8,
661 drwav_acid_flag_acidizer = 16 /* Not sure what this means. */
662} drwav_acid_flag;
663
664typedef struct
665{
666 /* A bit-field, see drwav_acid_flag. */
667 drwav_uint32 flags;
668
669 /* Valid if flags contains drwav_acid_flag_root_note_set. It represents the MIDI root note the file - a value from 0 to 127. */
670 drwav_uint16 midiUnityNote;
671
672 /* Reserved values that should probably be ignored. reserved1 seems to often be 128 and reserved2 is 0. */
673 drwav_uint16 reserved1;
674 float reserved2;
675
676 /* Number of beats. */
677 drwav_uint32 numBeats;
678
679 /* The time signature of the audio. */
680 drwav_uint16 meterDenominator;
681 drwav_uint16 meterNumerator;
682
683 /* Beats per minute of the track. Setting a value of 0 suggests that there is no tempo. */
684 float tempo;
685} drwav_acid;
686
687/*
688Cue Label or Note metadata
689
690These are 2 different types of metadata, but they have the exact same format. Labels tend to be the
691more common and represent a short name for a cue point. Notes might be used to represent a longer
692comment.
693*/
694typedef struct
695{
696 /* The ID of a cue point that this label or note corresponds to. */
697 drwav_uint32 cuePointId;
698
699 /* Size of the string not including any null terminator. */
700 drwav_uint32 stringLength;
701
702 /* The string. The *init_with_metadata functions null terminate this for convenience. */
703 char* pString;
704} drwav_list_label_or_note;
705
706/*
707BEXT metadata, also known as Broadcast Wave Format (BWF)
708
709This metadata adds some extra description to an audio file. You must check the version field to
710determine if the UMID or the loudness fields are valid.
711*/
712typedef struct
713{
714 /*
715 These top 3 fields, and the umid field are actually defined in the standard as a statically
716 sized buffers. In order to reduce the size of this struct (and therefore the union in the
717 metadata struct), we instead store these as pointers.
718 */
719 char* pDescription; /* Can be NULL or a null-terminated string, must be <= 256 characters. */
720 char* pOriginatorName; /* Can be NULL or a null-terminated string, must be <= 32 characters. */
721 char* pOriginatorReference; /* Can be NULL or a null-terminated string, must be <= 32 characters. */
722 char pOriginationDate[10]; /* ASCII "yyyy:mm:dd". */
723 char pOriginationTime[8]; /* ASCII "hh:mm:ss". */
724 drwav_uint64 timeReference; /* First sample count since midnight. */
725 drwav_uint16 version; /* Version of the BWF, check this to see if the fields below are valid. */
726
727 /*
728 Unrestricted ASCII characters containing a collection of strings terminated by CR/LF. Each
729 string shall contain a description of a coding process applied to the audio data.
730 */
731 char* pCodingHistory;
732 drwav_uint32 codingHistorySize;
733
734 /* Fields below this point are only valid if the version is 1 or above. */
735 drwav_uint8* pUMID; /* Exactly 64 bytes of SMPTE UMID */
736
737 /* Fields below this point are only valid if the version is 2 or above. */
738 drwav_uint16 loudnessValue; /* Integrated Loudness Value of the file in LUFS (multiplied by 100). */
739 drwav_uint16 loudnessRange; /* Loudness Range of the file in LU (multiplied by 100). */
740 drwav_uint16 maxTruePeakLevel; /* Maximum True Peak Level of the file expressed as dBTP (multiplied by 100). */
741 drwav_uint16 maxMomentaryLoudness; /* Highest value of the Momentary Loudness Level of the file in LUFS (multiplied by 100). */
742 drwav_uint16 maxShortTermLoudness; /* Highest value of the Short-Term Loudness Level of the file in LUFS (multiplied by 100). */
743} drwav_bext;
744
745/*
746Info Text Metadata
747
748There a many different types of information text that can be saved in this format. This is where
749things like the album name, the artists, the year it was produced, etc are saved. See
750drwav_metadata_type for the full list of types that dr_wav supports.
751*/
752typedef struct
753{
754 /* Size of the string not including any null terminator. */
755 drwav_uint32 stringLength;
756
757 /* The string. The *init_with_metadata functions null terminate this for convenience. */
758 char* pString;
759} drwav_list_info_text;
760
761/*
762Labelled Cue Region Metadata
763
764The labelled cue region metadata is used to associate some region of audio with text. The region
765starts at a cue point, and extends for the given number of samples.
766*/
767typedef struct
768{
769 /* The ID of a cue point that this object corresponds to. */
770 drwav_uint32 cuePointId;
771
772 /* The number of samples from the cue point forwards that should be considered this region */
773 drwav_uint32 sampleLength;
774
775 /* Four characters used to say what the purpose of this region is. */
776 drwav_uint8 purposeId[4];
777
778 /* Unsure of the exact meanings of these. It appears to be acceptable to set them all to 0. */
779 drwav_uint16 country;
780 drwav_uint16 language;
781 drwav_uint16 dialect;
782 drwav_uint16 codePage;
783
784 /* Size of the string not including any null terminator. */
785 drwav_uint32 stringLength;
786
787 /* The string. The *init_with_metadata functions null terminate this for convenience. */
788 char* pString;
789} drwav_list_labelled_cue_region;
790
791/*
792Unknown Metadata
793
794This chunk just represents a type of chunk that dr_wav does not understand.
795
796Unknown metadata has a location attached to it. This is because wav files can have a LIST chunk
797that contains subchunks. These LIST chunks can be one of two types. An adtl list, or an INFO
798list. This enum is used to specify the location of a chunk that dr_wav currently doesn't support.
799*/
800typedef enum
801{
802 drwav_metadata_location_invalid,
803 drwav_metadata_location_top_level,
804 drwav_metadata_location_inside_info_list,
805 drwav_metadata_location_inside_adtl_list
806} drwav_metadata_location;
807
808typedef struct
809{
810 drwav_uint8 id[4];
811 drwav_metadata_location chunkLocation;
812 drwav_uint32 dataSizeInBytes;
813 drwav_uint8* pData;
814} drwav_unknown_metadata;
815
816/*
817Metadata is saved as a union of all the supported types.
818*/
819typedef struct
820{
821 /* Determines which item in the union is valid. */
822 drwav_metadata_type type;
823
824 union
825 {
826 drwav_cue cue;
827 drwav_smpl smpl;
828 drwav_acid acid;
829 drwav_inst inst;
830 drwav_bext bext;
831 drwav_list_label_or_note labelOrNote; /* List label or list note. */
832 drwav_list_labelled_cue_region labelledCueRegion;
833 drwav_list_info_text infoText; /* Any of the list info types. */
834 drwav_unknown_metadata unknown;
835 } data;
836} drwav_metadata;
837
838typedef struct
839{
840 /* A pointer to the function to call when more data is needed. */
841 drwav_read_proc onRead;
842
843 /* A pointer to the function to call when data needs to be written. Only used when the drwav object is opened in write mode. */
844 drwav_write_proc onWrite;
845
846 /* A pointer to the function to call when the wav file needs to be seeked. */
847 drwav_seek_proc onSeek;
848
849 /* The user data to pass to callbacks. */
850 void* pUserData;
851
852 /* Allocation callbacks. */
853 drwav_allocation_callbacks allocationCallbacks;
854
855
856 /* Whether or not the WAV file is formatted as a standard RIFF file or W64. */
857 drwav_container container;
858
859
860 /* Structure containing format information exactly as specified by the wav file. */
861 drwav_fmt fmt;
862
863 /* The sample rate. Will be set to something like 44100. */
864 drwav_uint32 sampleRate;
865
866 /* The number of channels. This will be set to 1 for monaural streams, 2 for stereo, etc. */
867 drwav_uint16 channels;
868
869 /* The bits per sample. Will be set to something like 16, 24, etc. */
870 drwav_uint16 bitsPerSample;
871
872 /* Equal to fmt.formatTag, or the value specified by fmt.subFormat if fmt.formatTag is equal to 65534 (WAVE_FORMAT_EXTENSIBLE). */
873 drwav_uint16 translatedFormatTag;
874
875 /* The total number of PCM frames making up the audio data. */
876 drwav_uint64 totalPCMFrameCount;
877
878
879 /* The size in bytes of the data chunk. */
880 drwav_uint64 dataChunkDataSize;
881
882 /* The position in the stream of the first data byte of the data chunk. This is used for seeking. */
883 drwav_uint64 dataChunkDataPos;
884
885 /* The number of bytes remaining in the data chunk. */
886 drwav_uint64 bytesRemaining;
887
888 /* The current read position in PCM frames. */
889 drwav_uint64 readCursorInPCMFrames;
890
891
892 /*
893 Only used in sequential write mode. Keeps track of the desired size of the "data" chunk at the point of initialization time. Always
894 set to 0 for non-sequential writes and when the drwav object is opened in read mode. Used for validation.
895 */
896 drwav_uint64 dataChunkDataSizeTargetWrite;
897
898 /* Keeps track of whether or not the wav writer was initialized in sequential mode. */
899 drwav_bool32 isSequentialWrite;
900
901
902 /* A array of metadata. This is valid after the *init_with_metadata call returns. It will be valid until drwav_uninit() is called. You can take ownership of this data with drwav_take_ownership_of_metadata(). */
903 drwav_metadata* pMetadata;
904 drwav_uint32 metadataCount;
905
906
907 /* A hack to avoid a DRWAV_MALLOC() when opening a decoder with drwav_init_memory(). */
908 drwav__memory_stream memoryStream;
909 drwav__memory_stream_write memoryStreamWrite;
910
911
912 /* Microsoft ADPCM specific data. */
913 struct
914 {
915 drwav_uint32 bytesRemainingInBlock;
916 drwav_uint16 predictor[2];
917 drwav_int32 delta[2];
918 drwav_int32 cachedFrames[4]; /* Samples are stored in this cache during decoding. */
919 drwav_uint32 cachedFrameCount;
920 drwav_int32 prevFrames[2][2]; /* The previous 2 samples for each channel (2 channels at most). */
921 } msadpcm;
922
923 /* IMA ADPCM specific data. */
924 struct
925 {
926 drwav_uint32 bytesRemainingInBlock;
927 drwav_int32 predictor[2];
928 drwav_int32 stepIndex[2];
929 drwav_int32 cachedFrames[16]; /* Samples are stored in this cache during decoding. */
930 drwav_uint32 cachedFrameCount;
931 } ima;
932
933 /* AIFF specific data. */
934 struct
935 {
936 drwav_bool8 isLE; /* Will be set to true if the audio data is little-endian encoded. */
937 drwav_bool8 isUnsigned; /* Only used for 8-bit samples. When set to true, will be treated as unsigned. */
938 } aiff;
939} drwav;
940
941
942/*
943Initializes a pre-allocated drwav object for reading.
944
945pWav [out] A pointer to the drwav object being initialized.
946onRead [in] The function to call when data needs to be read from the client.
947onSeek [in] The function to call when the read position of the client data needs to move.
948onChunk [in, optional] The function to call when a chunk is enumerated at initialized time.
949pUserData, pReadSeekUserData [in, optional] A pointer to application defined data that will be passed to onRead and onSeek.
950pChunkUserData [in, optional] A pointer to application defined data that will be passed to onChunk.
951flags [in, optional] A set of flags for controlling how things are loaded.
952
953Returns true if successful; false otherwise.
954
955Close the loader with drwav_uninit().
956
957This is the lowest level function for initializing a WAV file. You can also use drwav_init_file() and drwav_init_memory()
958to open the stream from a file or from a block of memory respectively.
959
960Possible values for flags:
961 DRWAV_SEQUENTIAL: Never perform a backwards seek while loading. This disables the chunk callback and will cause this function
962 to return as soon as the data chunk is found. Any chunks after the data chunk will be ignored.
963
964drwav_init() is equivalent to "drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0);".
965
966The onChunk callback is not called for the WAVE or FMT chunks. The contents of the FMT chunk can be read from pWav->fmt
967after the function returns.
968
969See also: drwav_init_file(), drwav_init_memory(), drwav_uninit()
970*/
971DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
972DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
973DRWAV_API drwav_bool32 drwav_init_with_metadata(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
974
975/*
976Initializes a pre-allocated drwav object for writing.
977
978onWrite [in] The function to call when data needs to be written.
979onSeek [in] The function to call when the write position needs to move.
980pUserData [in, optional] A pointer to application defined data that will be passed to onWrite and onSeek.
981metadata, numMetadata [in, optional] An array of metadata objects that should be written to the file. The array is not edited. You are responsible for this metadata memory and it must maintain valid until drwav_uninit() is called.
982
983Returns true if successful; false otherwise.
984
985Close the writer with drwav_uninit().
986
987This is the lowest level function for initializing a WAV file. You can also use drwav_init_file_write() and drwav_init_memory_write()
988to open the stream from a file or from a block of memory respectively.
989
990If the total sample count is known, you can use drwav_init_write_sequential(). This avoids the need for dr_wav to perform
991a post-processing step for storing the total sample count and the size of the data chunk which requires a backwards seek.
992
993See also: drwav_init_file_write(), drwav_init_memory_write(), drwav_uninit()
994*/
995DRWAV_API drwav_bool32 drwav_init_write(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
996DRWAV_API drwav_bool32 drwav_init_write_sequential(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
997DRWAV_API drwav_bool32 drwav_init_write_sequential_pcm_frames(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
998DRWAV_API drwav_bool32 drwav_init_write_with_metadata(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks, drwav_metadata* pMetadata, drwav_uint32 metadataCount);
999
1000/*
1001Utility function to determine the target size of the entire data to be written (including all headers and chunks).
1002
1003Returns the target size in bytes.
1004
1005The metadata argument can be NULL meaning no metadata exists.
1006
1007Useful if the application needs to know the size to allocate.
1008
1009Only writing to the RIFF chunk and one data chunk is currently supported.
1010
1011See also: drwav_init_write(), drwav_init_file_write(), drwav_init_memory_write()
1012*/
1013DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalFrameCount, drwav_metadata* pMetadata, drwav_uint32 metadataCount);
1014
1015/*
1016Take ownership of the metadata objects that were allocated via one of the init_with_metadata() function calls. The init_with_metdata functions perform a single heap allocation for this metadata.
1017
1018Useful if you want the data to persist beyond the lifetime of the drwav object.
1019
1020You must free the data returned from this function using drwav_free().
1021*/
1022DRWAV_API drwav_metadata* drwav_take_ownership_of_metadata(drwav* pWav);
1023
1024/*
1025Uninitializes the given drwav object.
1026
1027Use this only for objects initialized with drwav_init*() functions (drwav_init(), drwav_init_ex(), drwav_init_write(), drwav_init_write_sequential()).
1028*/
1029DRWAV_API drwav_result drwav_uninit(drwav* pWav);
1030
1031
1032/*
1033Reads raw audio data.
1034
1035This is the lowest level function for reading audio data. It simply reads the given number of
1036bytes of the raw internal sample data.
1037
1038Consider using drwav_read_pcm_frames_s16(), drwav_read_pcm_frames_s32() or drwav_read_pcm_frames_f32() for
1039reading sample data in a consistent format.
1040
1041pBufferOut can be NULL in which case a seek will be performed.
1042
1043Returns the number of bytes actually read.
1044*/
1045DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut);
1046
1047/*
1048Reads up to the specified number of PCM frames from the WAV file.
1049
1050The output data will be in the file's internal format, converted to native-endian byte order. Use
1051drwav_read_pcm_frames_s16/f32/s32() to read data in a specific format.
1052
1053If the return value is less than <framesToRead> it means the end of the file has been reached or
1054you have requested more PCM frames than can possibly fit in the output buffer.
1055
1056This function will only work when sample data is of a fixed size and uncompressed. If you are
1057using a compressed format consider using drwav_read_raw() or drwav_read_pcm_frames_s16/s32/f32().
1058
1059pBufferOut can be NULL in which case a seek will be performed.
1060*/
1061DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
1062DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
1063DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut);
1064
1065/*
1066Seeks to the given PCM frame.
1067
1068Returns true if successful; false otherwise.
1069*/
1070DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex);
1071
1072/*
1073Retrieves the current read position in pcm frames.
1074*/
1075DRWAV_API drwav_result drwav_get_cursor_in_pcm_frames(drwav* pWav, drwav_uint64* pCursor);
1076
1077/*
1078Retrieves the length of the file.
1079*/
1080DRWAV_API drwav_result drwav_get_length_in_pcm_frames(drwav* pWav, drwav_uint64* pLength);
1081
1082
1083/*
1084Writes raw audio data.
1085
1086Returns the number of bytes actually written. If this differs from bytesToWrite, it indicates an error.
1087*/
1088DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData);
1089
1090/*
1091Writes PCM frames.
1092
1093Returns the number of PCM frames written.
1094
1095Input samples need to be in native-endian byte order. On big-endian architectures the input data will be converted to
1096little-endian. Use drwav_write_raw() to write raw audio data without performing any conversion.
1097*/
1098DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
1099DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
1100DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData);
1101
1102/* Conversion Utilities */
1103#ifndef DR_WAV_NO_CONVERSION_API
1104
1105/*
1106Reads a chunk of audio data and converts it to signed 16-bit PCM samples.
1107
1108pBufferOut can be NULL in which case a seek will be performed.
1109
1110Returns the number of PCM frames actually read.
1111
1112If the return value is less than <framesToRead> it means the end of the file has been reached.
1113*/
1114DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
1115DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
1116DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut);
1117
1118/* Low-level function for converting unsigned 8-bit PCM samples to signed 16-bit PCM samples. */
1119DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
1120
1121/* Low-level function for converting signed 24-bit PCM samples to signed 16-bit PCM samples. */
1122DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
1123
1124/* Low-level function for converting signed 32-bit PCM samples to signed 16-bit PCM samples. */
1125DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount);
1126
1127/* Low-level function for converting IEEE 32-bit floating point samples to signed 16-bit PCM samples. */
1128DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount);
1129
1130/* Low-level function for converting IEEE 64-bit floating point samples to signed 16-bit PCM samples. */
1131DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount);
1132
1133/* Low-level function for converting A-law samples to signed 16-bit PCM samples. */
1134DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
1135
1136/* Low-level function for converting u-law samples to signed 16-bit PCM samples. */
1137DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
1138
1139
1140/*
1141Reads a chunk of audio data and converts it to IEEE 32-bit floating point samples.
1142
1143pBufferOut can be NULL in which case a seek will be performed.
1144
1145Returns the number of PCM frames actually read.
1146
1147If the return value is less than <framesToRead> it means the end of the file has been reached.
1148*/
1149DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
1150DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
1151DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut);
1152
1153/* Low-level function for converting unsigned 8-bit PCM samples to IEEE 32-bit floating point samples. */
1154DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
1155
1156/* Low-level function for converting signed 16-bit PCM samples to IEEE 32-bit floating point samples. */
1157DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount);
1158
1159/* Low-level function for converting signed 24-bit PCM samples to IEEE 32-bit floating point samples. */
1160DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
1161
1162/* Low-level function for converting signed 32-bit PCM samples to IEEE 32-bit floating point samples. */
1163DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount);
1164
1165/* Low-level function for converting IEEE 64-bit floating point samples to IEEE 32-bit floating point samples. */
1166DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount);
1167
1168/* Low-level function for converting A-law samples to IEEE 32-bit floating point samples. */
1169DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
1170
1171/* Low-level function for converting u-law samples to IEEE 32-bit floating point samples. */
1172DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
1173
1174
1175/*
1176Reads a chunk of audio data and converts it to signed 32-bit PCM samples.
1177
1178pBufferOut can be NULL in which case a seek will be performed.
1179
1180Returns the number of PCM frames actually read.
1181
1182If the return value is less than <framesToRead> it means the end of the file has been reached.
1183*/
1184DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
1185DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
1186DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut);
1187
1188/* Low-level function for converting unsigned 8-bit PCM samples to signed 32-bit PCM samples. */
1189DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
1190
1191/* Low-level function for converting signed 16-bit PCM samples to signed 32-bit PCM samples. */
1192DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount);
1193
1194/* Low-level function for converting signed 24-bit PCM samples to signed 32-bit PCM samples. */
1195DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
1196
1197/* Low-level function for converting IEEE 32-bit floating point samples to signed 32-bit PCM samples. */
1198DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount);
1199
1200/* Low-level function for converting IEEE 64-bit floating point samples to signed 32-bit PCM samples. */
1201DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount);
1202
1203/* Low-level function for converting A-law samples to signed 32-bit PCM samples. */
1204DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
1205
1206/* Low-level function for converting u-law samples to signed 32-bit PCM samples. */
1207DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
1208
1209#endif /* DR_WAV_NO_CONVERSION_API */
1210
1211
1212/* High-Level Convenience Helpers */
1213
1214#ifndef DR_WAV_NO_STDIO
1215/*
1216Helper for initializing a wave file for reading using stdio.
1217
1218This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav
1219objects because the operating system may restrict the number of file handles an application can have open at
1220any given time.
1221*/
1222DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks);
1223DRWAV_API drwav_bool32 drwav_init_file_ex(drwav* pWav, const char* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
1224DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks);
1225DRWAV_API drwav_bool32 drwav_init_file_ex_w(drwav* pWav, const wchar_t* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
1226DRWAV_API drwav_bool32 drwav_init_file_with_metadata(drwav* pWav, const char* filename, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
1227DRWAV_API drwav_bool32 drwav_init_file_with_metadata_w(drwav* pWav, const wchar_t* filename, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
1228
1229
1230/*
1231Helper for initializing a wave file for writing using stdio.
1232
1233This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav
1234objects because the operating system may restrict the number of file handles an application can have open at
1235any given time.
1236*/
1237DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks);
1238DRWAV_API drwav_bool32 drwav_init_file_write_sequential(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks);
1239DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks);
1240DRWAV_API drwav_bool32 drwav_init_file_write_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks);
1241DRWAV_API drwav_bool32 drwav_init_file_write_sequential_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks);
1242DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks);
1243#endif /* DR_WAV_NO_STDIO */
1244
1245/*
1246Helper for initializing a loader from a pre-allocated memory buffer.
1247
1248This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for
1249the lifetime of the drwav object.
1250
1251The buffer should contain the contents of the entire wave file, not just the sample data.
1252*/
1253DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks);
1254DRWAV_API drwav_bool32 drwav_init_memory_ex(drwav* pWav, const void* data, size_t dataSize, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
1255DRWAV_API drwav_bool32 drwav_init_memory_with_metadata(drwav* pWav, const void* data, size_t dataSize, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
1256
1257/*
1258Helper for initializing a writer which outputs data to a memory buffer.
1259
1260dr_wav will manage the memory allocations, however it is up to the caller to free the data with drwav_free().
1261
1262The buffer will remain allocated even after drwav_uninit() is called. The buffer should not be considered valid
1263until after drwav_uninit() has been called.
1264*/
1265DRWAV_API drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks);
1266DRWAV_API drwav_bool32 drwav_init_memory_write_sequential(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks);
1267DRWAV_API drwav_bool32 drwav_init_memory_write_sequential_pcm_frames(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks);
1268
1269
1270#ifndef DR_WAV_NO_CONVERSION_API
1271/*
1272Opens and reads an entire wav file in a single operation.
1273
1274The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer.
1275*/
1276DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
1277DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
1278DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
1279#ifndef DR_WAV_NO_STDIO
1280/*
1281Opens and decodes an entire wav file in a single operation.
1282
1283The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer.
1284*/
1285DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
1286DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
1287DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
1288DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
1289DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
1290DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
1291#endif
1292/*
1293Opens and decodes an entire wav file from a block of memory in a single operation.
1294
1295The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer.
1296*/
1297DRWAV_API drwav_int16* drwav_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
1298DRWAV_API float* drwav_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
1299DRWAV_API drwav_int32* drwav_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks);
1300#endif
1301
1302/* Frees data that was allocated internally by dr_wav. */
1303DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks);
1304
1305/* Converts bytes from a wav stream to a sized type of native endian. */
1306DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data);
1307DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data);
1308DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data);
1309DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data);
1310DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data);
1311DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data);
1312DRWAV_API float drwav_bytes_to_f32(const drwav_uint8* data);
1313
1314/* Compares a GUID for the purpose of checking the type of a Wave64 chunk. */
1315DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16]);
1316
1317/* Compares a four-character-code for the purpose of checking the type of a RIFF chunk. */
1318DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b);
1319
1320#ifdef __cplusplus
1321}
1322#endif
1323#endif /* dr_wav_h */
1324
1325
1326/************************************************************************************************************************************************************
1327 ************************************************************************************************************************************************************
1328
1329 IMPLEMENTATION
1330
1331 ************************************************************************************************************************************************************
1332 ************************************************************************************************************************************************************/
1333#if defined(DR_WAV_IMPLEMENTATION) || defined(DRWAV_IMPLEMENTATION)
1334#ifndef dr_wav_c
1335#define dr_wav_c
1336
1337#ifdef __MRC__
1338/* MrC currently doesn't compile dr_wav correctly with any optimizations enabled. */
1339#pragma options opt off
1340#endif
1341
1342#include <stdlib.h>
1343#include <string.h>
1344#include <limits.h> /* For INT_MAX */
1345
1346#ifndef DR_WAV_NO_STDIO
1347#include <stdio.h>
1348#ifndef DR_WAV_NO_WCHAR
1349#include <wchar.h>
1350#endif
1351#endif
1352
1353/* Standard library stuff. */
1354#ifndef DRWAV_ASSERT
1355#include <assert.h>
1356#define DRWAV_ASSERT(expression) assert(expression)
1357#endif
1358#ifndef DRWAV_MALLOC
1359#define DRWAV_MALLOC(sz) malloc((sz))
1360#endif
1361#ifndef DRWAV_REALLOC
1362#define DRWAV_REALLOC(p, sz) realloc((p), (sz))
1363#endif
1364#ifndef DRWAV_FREE
1365#define DRWAV_FREE(p) free((p))
1366#endif
1367#ifndef DRWAV_COPY_MEMORY
1368#define DRWAV_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz))
1369#endif
1370#ifndef DRWAV_ZERO_MEMORY
1371#define DRWAV_ZERO_MEMORY(p, sz) memset((p), 0, (sz))
1372#endif
1373#ifndef DRWAV_ZERO_OBJECT
1374#define DRWAV_ZERO_OBJECT(p) DRWAV_ZERO_MEMORY((p), sizeof(*p))
1375#endif
1376
1377#define drwav_countof(x) (sizeof(x) / sizeof(x[0]))
1378#define drwav_align(x, a) ((((x) + (a) - 1) / (a)) * (a))
1379#define drwav_min(a, b) (((a) < (b)) ? (a) : (b))
1380#define drwav_max(a, b) (((a) > (b)) ? (a) : (b))
1381#define drwav_clamp(x, lo, hi) (drwav_max((lo), drwav_min((hi), (x))))
1382#define drwav_offset_ptr(p, offset) (((drwav_uint8*)(p)) + (offset))
1383
1384#define DRWAV_MAX_SIMD_VECTOR_SIZE 32
1385
1386/* Architecture Detection */
1387#if defined(__x86_64__) || defined(_M_X64)
1388 #define DRWAV_X64
1389#elif defined(__i386) || defined(_M_IX86)
1390 #define DRWAV_X86
1391#elif defined(__arm__) || defined(_M_ARM)
1392 #define DRWAV_ARM
1393#endif
1394/* End Architecture Detection */
1395
1396/* Inline */
1397#ifdef _MSC_VER
1398 #define DRWAV_INLINE __forceinline
1399#elif defined(__GNUC__)
1400 /*
1401 I've had a bug report where GCC is emitting warnings about functions possibly not being inlineable. This warning happens when
1402 the __attribute__((always_inline)) attribute is defined without an "inline" statement. I think therefore there must be some
1403 case where "__inline__" is not always defined, thus the compiler emitting these warnings. When using -std=c89 or -ansi on the
1404 command line, we cannot use the "inline" keyword and instead need to use "__inline__". In an attempt to work around this issue
1405 I am using "__inline__" only when we're compiling in strict ANSI mode.
1406 */
1407 #if defined(__STRICT_ANSI__)
1408 #define DRWAV_GNUC_INLINE_HINT __inline__
1409 #else
1410 #define DRWAV_GNUC_INLINE_HINT inline
1411 #endif
1412
1413 #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)) || defined(__clang__)
1414 #define DRWAV_INLINE DRWAV_GNUC_INLINE_HINT __attribute__((always_inline))
1415 #else
1416 #define DRWAV_INLINE DRWAV_GNUC_INLINE_HINT
1417 #endif
1418#elif defined(__WATCOMC__)
1419 #define DRWAV_INLINE __inline
1420#else
1421 #define DRWAV_INLINE
1422#endif
1423/* End Inline */
1424
1425/* SIZE_MAX */
1426#if defined(SIZE_MAX)
1427 #define DRWAV_SIZE_MAX SIZE_MAX
1428#else
1429 #if defined(_WIN64) || defined(_LP64) || defined(__LP64__)
1430 #define DRWAV_SIZE_MAX ((drwav_uint64)0xFFFFFFFFFFFFFFFF)
1431 #else
1432 #define DRWAV_SIZE_MAX 0xFFFFFFFF
1433 #endif
1434#endif
1435/* End SIZE_MAX */
1436
1437/* Weird bit manipulation is for C89 compatibility (no direct support for 64-bit integers). */
1438#define DRWAV_INT64_MIN ((drwav_int64) ((drwav_uint64)0x80000000 << 32))
1439#define DRWAV_INT64_MAX ((drwav_int64)(((drwav_uint64)0x7FFFFFFF << 32) | 0xFFFFFFFF))
1440
1441#if defined(_MSC_VER) && _MSC_VER >= 1400
1442 #define DRWAV_HAS_BYTESWAP16_INTRINSIC
1443 #define DRWAV_HAS_BYTESWAP32_INTRINSIC
1444 #define DRWAV_HAS_BYTESWAP64_INTRINSIC
1445#elif defined(__clang__)
1446 #if defined(__has_builtin)
1447 #if __has_builtin(__builtin_bswap16)
1448 #define DRWAV_HAS_BYTESWAP16_INTRINSIC
1449 #endif
1450 #if __has_builtin(__builtin_bswap32)
1451 #define DRWAV_HAS_BYTESWAP32_INTRINSIC
1452 #endif
1453 #if __has_builtin(__builtin_bswap64)
1454 #define DRWAV_HAS_BYTESWAP64_INTRINSIC
1455 #endif
1456 #endif
1457#elif defined(__GNUC__)
1458 #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
1459 #define DRWAV_HAS_BYTESWAP32_INTRINSIC
1460 #define DRWAV_HAS_BYTESWAP64_INTRINSIC
1461 #endif
1462 #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
1463 #define DRWAV_HAS_BYTESWAP16_INTRINSIC
1464 #endif
1465#endif
1466
1467DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision)
1468{
1469 if (pMajor) {
1470 *pMajor = DRWAV_VERSION_MAJOR;
1471 }
1472
1473 if (pMinor) {
1474 *pMinor = DRWAV_VERSION_MINOR;
1475 }
1476
1477 if (pRevision) {
1478 *pRevision = DRWAV_VERSION_REVISION;
1479 }
1480}
1481
1482DRWAV_API const char* drwav_version_string(void)
1483{
1484 return DRWAV_VERSION_STRING;
1485}
1486
1487/*
1488These limits are used for basic validation when initializing the decoder. If you exceed these limits, first of all: what on Earth are
1489you doing?! (Let me know, I'd be curious!) Second, you can adjust these by #define-ing them before the dr_wav implementation.
1490*/
1491#ifndef DRWAV_MAX_SAMPLE_RATE
1492#define DRWAV_MAX_SAMPLE_RATE 384000
1493#endif
1494#ifndef DRWAV_MAX_CHANNELS
1495#define DRWAV_MAX_CHANNELS 256
1496#endif
1497#ifndef DRWAV_MAX_BITS_PER_SAMPLE
1498#define DRWAV_MAX_BITS_PER_SAMPLE 64
1499#endif
1500
1501static const drwav_uint8 drwavGUID_W64_RIFF[16] = {0x72,0x69,0x66,0x66, 0x2E,0x91, 0xCF,0x11, 0xA5,0xD6, 0x28,0xDB,0x04,0xC1,0x00,0x00}; /* 66666972-912E-11CF-A5D6-28DB04C10000 */
1502static const drwav_uint8 drwavGUID_W64_WAVE[16] = {0x77,0x61,0x76,0x65, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 65766177-ACF3-11D3-8CD1-00C04F8EDB8A */
1503/*static const drwav_uint8 drwavGUID_W64_JUNK[16] = {0x6A,0x75,0x6E,0x6B, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A};*/ /* 6B6E756A-ACF3-11D3-8CD1-00C04F8EDB8A */
1504static const drwav_uint8 drwavGUID_W64_FMT [16] = {0x66,0x6D,0x74,0x20, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A */
1505static const drwav_uint8 drwavGUID_W64_FACT[16] = {0x66,0x61,0x63,0x74, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 74636166-ACF3-11D3-8CD1-00C04F8EDB8A */
1506static const drwav_uint8 drwavGUID_W64_DATA[16] = {0x64,0x61,0x74,0x61, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 61746164-ACF3-11D3-8CD1-00C04F8EDB8A */
1507/*static const drwav_uint8 drwavGUID_W64_SMPL[16] = {0x73,0x6D,0x70,0x6C, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A};*/ /* 6C706D73-ACF3-11D3-8CD1-00C04F8EDB8A */
1508
1509
1510static DRWAV_INLINE int drwav__is_little_endian(void)
1511{
1512#if defined(DRWAV_X86) || defined(DRWAV_X64)
1513 return DRWAV_TRUE;
1514#elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN
1515 return DRWAV_TRUE;
1516#else
1517 int n = 1;
1518 return (*(char*)&n) == 1;
1519#endif
1520}
1521
1522
1523static DRWAV_INLINE void drwav_bytes_to_guid(const drwav_uint8* data, drwav_uint8* guid)
1524{
1525 int i;
1526 for (i = 0; i < 16; ++i) {
1527 guid[i] = data[i];
1528 }
1529}
1530
1531
1532static DRWAV_INLINE drwav_uint16 drwav__bswap16(drwav_uint16 n)
1533{
1534#ifdef DRWAV_HAS_BYTESWAP16_INTRINSIC
1535 #if defined(_MSC_VER)
1536 return _byteswap_ushort(n);
1537 #elif defined(__GNUC__) || defined(__clang__)
1538 return __builtin_bswap16(n);
1539 #else
1540 #error "This compiler does not support the byte swap intrinsic."
1541 #endif
1542#else
1543 return ((n & 0xFF00) >> 8) |
1544 ((n & 0x00FF) << 8);
1545#endif
1546}
1547
1548static DRWAV_INLINE drwav_uint32 drwav__bswap32(drwav_uint32 n)
1549{
1550#ifdef DRWAV_HAS_BYTESWAP32_INTRINSIC
1551 #if defined(_MSC_VER)
1552 return _byteswap_ulong(n);
1553 #elif defined(__GNUC__) || defined(__clang__)
1554 #if defined(DRWAV_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(DRWAV_64BIT) /* <-- 64-bit inline assembly has not been tested, so disabling for now. */
1555 /* Inline assembly optimized implementation for ARM. In my testing, GCC does not generate optimized code with __builtin_bswap32(). */
1556 drwav_uint32 r;
1557 __asm__ __volatile__ (
1558 #if defined(DRWAV_64BIT)
1559 "rev %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(n) /* <-- This is untested. If someone in the community could test this, that would be appreciated! */
1560 #else
1561 "rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n)
1562 #endif
1563 );
1564 return r;
1565 #else
1566 return __builtin_bswap32(n);
1567 #endif
1568 #else
1569 #error "This compiler does not support the byte swap intrinsic."
1570 #endif
1571#else
1572 return ((n & 0xFF000000) >> 24) |
1573 ((n & 0x00FF0000) >> 8) |
1574 ((n & 0x0000FF00) << 8) |
1575 ((n & 0x000000FF) << 24);
1576#endif
1577}
1578
1579static DRWAV_INLINE drwav_uint64 drwav__bswap64(drwav_uint64 n)
1580{
1581#ifdef DRWAV_HAS_BYTESWAP64_INTRINSIC
1582 #if defined(_MSC_VER)
1583 return _byteswap_uint64(n);
1584 #elif defined(__GNUC__) || defined(__clang__)
1585 return __builtin_bswap64(n);
1586 #else
1587 #error "This compiler does not support the byte swap intrinsic."
1588 #endif
1589#else
1590 /* Weird "<< 32" bitshift is required for C89 because it doesn't support 64-bit constants. Should be optimized out by a good compiler. */
1591 return ((n & ((drwav_uint64)0xFF000000 << 32)) >> 56) |
1592 ((n & ((drwav_uint64)0x00FF0000 << 32)) >> 40) |
1593 ((n & ((drwav_uint64)0x0000FF00 << 32)) >> 24) |
1594 ((n & ((drwav_uint64)0x000000FF << 32)) >> 8) |
1595 ((n & ((drwav_uint64)0xFF000000 )) << 8) |
1596 ((n & ((drwav_uint64)0x00FF0000 )) << 24) |
1597 ((n & ((drwav_uint64)0x0000FF00 )) << 40) |
1598 ((n & ((drwav_uint64)0x000000FF )) << 56);
1599#endif
1600}
1601
1602
1603static DRWAV_INLINE drwav_int16 drwav__bswap_s16(drwav_int16 n)
1604{
1605 return (drwav_int16)drwav__bswap16((drwav_uint16)n);
1606}
1607
1608static DRWAV_INLINE void drwav__bswap_samples_s16(drwav_int16* pSamples, drwav_uint64 sampleCount)
1609{
1610 drwav_uint64 iSample;
1611 for (iSample = 0; iSample < sampleCount; iSample += 1) {
1612 pSamples[iSample] = drwav__bswap_s16(pSamples[iSample]);
1613 }
1614}
1615
1616
1617static DRWAV_INLINE void drwav__bswap_s24(drwav_uint8* p)
1618{
1619 drwav_uint8 t;
1620 t = p[0];
1621 p[0] = p[2];
1622 p[2] = t;
1623}
1624
1625static DRWAV_INLINE void drwav__bswap_samples_s24(drwav_uint8* pSamples, drwav_uint64 sampleCount)
1626{
1627 drwav_uint64 iSample;
1628 for (iSample = 0; iSample < sampleCount; iSample += 1) {
1629 drwav_uint8* pSample = pSamples + (iSample*3);
1630 drwav__bswap_s24(pSample);
1631 }
1632}
1633
1634
1635static DRWAV_INLINE drwav_int32 drwav__bswap_s32(drwav_int32 n)
1636{
1637 return (drwav_int32)drwav__bswap32((drwav_uint32)n);
1638}
1639
1640static DRWAV_INLINE void drwav__bswap_samples_s32(drwav_int32* pSamples, drwav_uint64 sampleCount)
1641{
1642 drwav_uint64 iSample;
1643 for (iSample = 0; iSample < sampleCount; iSample += 1) {
1644 pSamples[iSample] = drwav__bswap_s32(pSamples[iSample]);
1645 }
1646}
1647
1648
1649static DRWAV_INLINE drwav_int64 drwav__bswap_s64(drwav_int64 n)
1650{
1651 return (drwav_int64)drwav__bswap64((drwav_uint64)n);
1652}
1653
1654static DRWAV_INLINE void drwav__bswap_samples_s64(drwav_int64* pSamples, drwav_uint64 sampleCount)
1655{
1656 drwav_uint64 iSample;
1657 for (iSample = 0; iSample < sampleCount; iSample += 1) {
1658 pSamples[iSample] = drwav__bswap_s64(pSamples[iSample]);
1659 }
1660}
1661
1662
1663static DRWAV_INLINE float drwav__bswap_f32(float n)
1664{
1665 union {
1666 drwav_uint32 i;
1667 float f;
1668 } x;
1669 x.f = n;
1670 x.i = drwav__bswap32(x.i);
1671
1672 return x.f;
1673}
1674
1675static DRWAV_INLINE void drwav__bswap_samples_f32(float* pSamples, drwav_uint64 sampleCount)
1676{
1677 drwav_uint64 iSample;
1678 for (iSample = 0; iSample < sampleCount; iSample += 1) {
1679 pSamples[iSample] = drwav__bswap_f32(pSamples[iSample]);
1680 }
1681}
1682
1683
1684static DRWAV_INLINE void drwav__bswap_samples(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample)
1685{
1686 switch (bytesPerSample)
1687 {
1688 case 1:
1689 {
1690 /* No-op. */
1691 } break;
1692 case 2:
1693 {
1694 drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount);
1695 } break;
1696 case 3:
1697 {
1698 drwav__bswap_samples_s24((drwav_uint8*)pSamples, sampleCount);
1699 } break;
1700 case 4:
1701 {
1702 drwav__bswap_samples_s32((drwav_int32*)pSamples, sampleCount);
1703 } break;
1704 case 8:
1705 {
1706 drwav__bswap_samples_s64((drwav_int64*)pSamples, sampleCount);
1707 } break;
1708 default:
1709 {
1710 /* Unsupported format. */
1711 DRWAV_ASSERT(DRWAV_FALSE);
1712 } break;
1713 }
1714}
1715
1716
1717
1718DRWAV_PRIVATE DRWAV_INLINE drwav_bool32 drwav_is_container_be(drwav_container container)
1719{
1720 if (container == drwav_container_rifx || container == drwav_container_aiff) {
1721 return DRWAV_TRUE;
1722 } else {
1723 return DRWAV_FALSE;
1724 }
1725}
1726
1727
1728DRWAV_PRIVATE DRWAV_INLINE drwav_uint16 drwav_bytes_to_u16_le(const drwav_uint8* data)
1729{
1730 return ((drwav_uint16)data[0] << 0) | ((drwav_uint16)data[1] << 8);
1731}
1732
1733DRWAV_PRIVATE DRWAV_INLINE drwav_uint16 drwav_bytes_to_u16_be(const drwav_uint8* data)
1734{
1735 return ((drwav_uint16)data[1] << 0) | ((drwav_uint16)data[0] << 8);
1736}
1737
1738DRWAV_PRIVATE DRWAV_INLINE drwav_uint16 drwav_bytes_to_u16_ex(const drwav_uint8* data, drwav_container container)
1739{
1740 if (drwav_is_container_be(container)) {
1741 return drwav_bytes_to_u16_be(data);
1742 } else {
1743 return drwav_bytes_to_u16_le(data);
1744 }
1745}
1746
1747
1748DRWAV_PRIVATE DRWAV_INLINE drwav_uint32 drwav_bytes_to_u32_le(const drwav_uint8* data)
1749{
1750 return ((drwav_uint32)data[0] << 0) | ((drwav_uint32)data[1] << 8) | ((drwav_uint32)data[2] << 16) | ((drwav_uint32)data[3] << 24);
1751}
1752
1753DRWAV_PRIVATE DRWAV_INLINE drwav_uint32 drwav_bytes_to_u32_be(const drwav_uint8* data)
1754{
1755 return ((drwav_uint32)data[3] << 0) | ((drwav_uint32)data[2] << 8) | ((drwav_uint32)data[1] << 16) | ((drwav_uint32)data[0] << 24);
1756}
1757
1758DRWAV_PRIVATE DRWAV_INLINE drwav_uint32 drwav_bytes_to_u32_ex(const drwav_uint8* data, drwav_container container)
1759{
1760 if (drwav_is_container_be(container)) {
1761 return drwav_bytes_to_u32_be(data);
1762 } else {
1763 return drwav_bytes_to_u32_le(data);
1764 }
1765}
1766
1767
1768
1769DRWAV_PRIVATE drwav_int64 drwav_aiff_extented_to_s64(const drwav_uint8* data)
1770{
1771 drwav_uint32 exponent = ((drwav_uint32)data[0] << 8) | data[1];
1772 drwav_uint64 hi = ((drwav_uint64)data[2] << 24) | ((drwav_uint64)data[3] << 16) | ((drwav_uint64)data[4] << 8) | ((drwav_uint64)data[5] << 0);
1773 drwav_uint64 lo = ((drwav_uint64)data[6] << 24) | ((drwav_uint64)data[7] << 16) | ((drwav_uint64)data[8] << 8) | ((drwav_uint64)data[9] << 0);
1774 drwav_uint64 significand = (hi << 32) | lo;
1775 int sign = exponent >> 15;
1776
1777 /* Remove sign bit. */
1778 exponent &= 0x7FFF;
1779
1780 /* Special cases. */
1781 if (exponent == 0 && significand == 0) {
1782 return 0;
1783 } else if (exponent == 0x7FFF) {
1784 return sign ? DRWAV_INT64_MIN : DRWAV_INT64_MAX; /* Infinite. */
1785 }
1786
1787 exponent -= 16383;
1788
1789 if (exponent > 63) {
1790 return sign ? DRWAV_INT64_MIN : DRWAV_INT64_MAX; /* Too big for a 64-bit integer. */
1791 } else if (exponent < 1) {
1792 return 0; /* Number is less than 1, so rounds down to 0. */
1793 }
1794
1795 significand >>= (63 - exponent);
1796
1797 if (sign) {
1798 return -(drwav_int64)significand;
1799 } else {
1800 return (drwav_int64)significand;
1801 }
1802}
1803
1804
1805DRWAV_PRIVATE void* drwav__malloc_default(size_t sz, void* pUserData)
1806{
1807 (void)pUserData;
1808 return DRWAV_MALLOC(sz);
1809}
1810
1811DRWAV_PRIVATE void* drwav__realloc_default(void* p, size_t sz, void* pUserData)
1812{
1813 (void)pUserData;
1814 return DRWAV_REALLOC(p, sz);
1815}
1816
1817DRWAV_PRIVATE void drwav__free_default(void* p, void* pUserData)
1818{
1819 (void)pUserData;
1820 DRWAV_FREE(p);
1821}
1822
1823
1824DRWAV_PRIVATE void* drwav__malloc_from_callbacks(size_t sz, const drwav_allocation_callbacks* pAllocationCallbacks)
1825{
1826 if (pAllocationCallbacks == NULL) {
1827 return NULL;
1828 }
1829
1830 if (pAllocationCallbacks->onMalloc != NULL) {
1831 return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData);
1832 }
1833
1834 /* Try using realloc(). */
1835 if (pAllocationCallbacks->onRealloc != NULL) {
1836 return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData);
1837 }
1838
1839 return NULL;
1840}
1841
1842DRWAV_PRIVATE void* drwav__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drwav_allocation_callbacks* pAllocationCallbacks)
1843{
1844 if (pAllocationCallbacks == NULL) {
1845 return NULL;
1846 }
1847
1848 if (pAllocationCallbacks->onRealloc != NULL) {
1849 return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData);
1850 }
1851
1852 /* Try emulating realloc() in terms of malloc()/free(). */
1853 if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) {
1854 void* p2;
1855
1856 p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData);
1857 if (p2 == NULL) {
1858 return NULL;
1859 }
1860
1861 if (p != NULL) {
1862 DRWAV_COPY_MEMORY(p2, p, szOld);
1863 pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
1864 }
1865
1866 return p2;
1867 }
1868
1869 return NULL;
1870}
1871
1872DRWAV_PRIVATE void drwav__free_from_callbacks(void* p, const drwav_allocation_callbacks* pAllocationCallbacks)
1873{
1874 if (p == NULL || pAllocationCallbacks == NULL) {
1875 return;
1876 }
1877
1878 if (pAllocationCallbacks->onFree != NULL) {
1879 pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
1880 }
1881}
1882
1883
1884DRWAV_PRIVATE drwav_allocation_callbacks drwav_copy_allocation_callbacks_or_defaults(const drwav_allocation_callbacks* pAllocationCallbacks)
1885{
1886 if (pAllocationCallbacks != NULL) {
1887 /* Copy. */
1888 return *pAllocationCallbacks;
1889 } else {
1890 /* Defaults. */
1891 drwav_allocation_callbacks allocationCallbacks;
1892 allocationCallbacks.pUserData = NULL;
1893 allocationCallbacks.onMalloc = drwav__malloc_default;
1894 allocationCallbacks.onRealloc = drwav__realloc_default;
1895 allocationCallbacks.onFree = drwav__free_default;
1896 return allocationCallbacks;
1897 }
1898}
1899
1900
1901static DRWAV_INLINE drwav_bool32 drwav__is_compressed_format_tag(drwav_uint16 formatTag)
1902{
1903 return
1904 formatTag == DR_WAVE_FORMAT_ADPCM ||
1905 formatTag == DR_WAVE_FORMAT_DVI_ADPCM;
1906}
1907
1908DRWAV_PRIVATE unsigned int drwav__chunk_padding_size_riff(drwav_uint64 chunkSize)
1909{
1910 return (unsigned int)(chunkSize % 2);
1911}
1912
1913DRWAV_PRIVATE unsigned int drwav__chunk_padding_size_w64(drwav_uint64 chunkSize)
1914{
1915 return (unsigned int)(chunkSize % 8);
1916}
1917
1918DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut);
1919DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut);
1920DRWAV_PRIVATE drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount);
1921
1922DRWAV_PRIVATE drwav_result drwav__read_chunk_header(drwav_read_proc onRead, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_chunk_header* pHeaderOut)
1923{
1924 if (container == drwav_container_riff || container == drwav_container_rifx || container == drwav_container_rf64 || container == drwav_container_aiff) {
1925 drwav_uint8 sizeInBytes[4];
1926
1927 if (onRead(pUserData, pHeaderOut->id.fourcc, 4) != 4) {
1928 return DRWAV_AT_END;
1929 }
1930
1931 if (onRead(pUserData, sizeInBytes, 4) != 4) {
1932 return DRWAV_INVALID_FILE;
1933 }
1934
1935 pHeaderOut->sizeInBytes = drwav_bytes_to_u32_ex(sizeInBytes, container);
1936 pHeaderOut->paddingSize = drwav__chunk_padding_size_riff(pHeaderOut->sizeInBytes);
1937
1938 *pRunningBytesReadOut += 8;
1939 } else if (container == drwav_container_w64) {
1940 drwav_uint8 sizeInBytes[8];
1941
1942 if (onRead(pUserData, pHeaderOut->id.guid, 16) != 16) {
1943 return DRWAV_AT_END;
1944 }
1945
1946 if (onRead(pUserData, sizeInBytes, 8) != 8) {
1947 return DRWAV_INVALID_FILE;
1948 }
1949
1950 pHeaderOut->sizeInBytes = drwav_bytes_to_u64(sizeInBytes) - 24; /* <-- Subtract 24 because w64 includes the size of the header. */
1951 pHeaderOut->paddingSize = drwav__chunk_padding_size_w64(pHeaderOut->sizeInBytes);
1952 *pRunningBytesReadOut += 24;
1953 } else {
1954 return DRWAV_INVALID_FILE;
1955 }
1956
1957 return DRWAV_SUCCESS;
1958}
1959
1960DRWAV_PRIVATE drwav_bool32 drwav__seek_forward(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData)
1961{
1962 drwav_uint64 bytesRemainingToSeek = offset;
1963 while (bytesRemainingToSeek > 0) {
1964 if (bytesRemainingToSeek > 0x7FFFFFFF) {
1965 if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) {
1966 return DRWAV_FALSE;
1967 }
1968 bytesRemainingToSeek -= 0x7FFFFFFF;
1969 } else {
1970 if (!onSeek(pUserData, (int)bytesRemainingToSeek, drwav_seek_origin_current)) {
1971 return DRWAV_FALSE;
1972 }
1973 bytesRemainingToSeek = 0;
1974 }
1975 }
1976
1977 return DRWAV_TRUE;
1978}
1979
1980DRWAV_PRIVATE drwav_bool32 drwav__seek_from_start(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData)
1981{
1982 if (offset <= 0x7FFFFFFF) {
1983 return onSeek(pUserData, (int)offset, drwav_seek_origin_start);
1984 }
1985
1986 /* Larger than 32-bit seek. */
1987 if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_start)) {
1988 return DRWAV_FALSE;
1989 }
1990 offset -= 0x7FFFFFFF;
1991
1992 for (;;) {
1993 if (offset <= 0x7FFFFFFF) {
1994 return onSeek(pUserData, (int)offset, drwav_seek_origin_current);
1995 }
1996
1997 if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) {
1998 return DRWAV_FALSE;
1999 }
2000 offset -= 0x7FFFFFFF;
2001 }
2002
2003 /* Should never get here. */
2004 /*return DRWAV_TRUE; */
2005}
2006
2007
2008
2009DRWAV_PRIVATE size_t drwav__on_read(drwav_read_proc onRead, void* pUserData, void* pBufferOut, size_t bytesToRead, drwav_uint64* pCursor)
2010{
2011 size_t bytesRead;
2012
2013 DRWAV_ASSERT(onRead != NULL);
2014 DRWAV_ASSERT(pCursor != NULL);
2015
2016 bytesRead = onRead(pUserData, pBufferOut, bytesToRead);
2017 *pCursor += bytesRead;
2018 return bytesRead;
2019}
2020
2021#if 0
2022DRWAV_PRIVATE drwav_bool32 drwav__on_seek(drwav_seek_proc onSeek, void* pUserData, int offset, drwav_seek_origin origin, drwav_uint64* pCursor)
2023{
2024 DRWAV_ASSERT(onSeek != NULL);
2025 DRWAV_ASSERT(pCursor != NULL);
2026
2027 if (!onSeek(pUserData, offset, origin)) {
2028 return DRWAV_FALSE;
2029 }
2030
2031 if (origin == drwav_seek_origin_start) {
2032 *pCursor = offset;
2033 } else {
2034 *pCursor += offset;
2035 }
2036
2037 return DRWAV_TRUE;
2038}
2039#endif
2040
2041
2042#define DRWAV_SMPL_BYTES 36
2043#define DRWAV_SMPL_LOOP_BYTES 24
2044#define DRWAV_INST_BYTES 7
2045#define DRWAV_ACID_BYTES 24
2046#define DRWAV_CUE_BYTES 4
2047#define DRWAV_BEXT_BYTES 602
2048#define DRWAV_BEXT_DESCRIPTION_BYTES 256
2049#define DRWAV_BEXT_ORIGINATOR_NAME_BYTES 32
2050#define DRWAV_BEXT_ORIGINATOR_REF_BYTES 32
2051#define DRWAV_BEXT_RESERVED_BYTES 180
2052#define DRWAV_BEXT_UMID_BYTES 64
2053#define DRWAV_CUE_POINT_BYTES 24
2054#define DRWAV_LIST_LABEL_OR_NOTE_BYTES 4
2055#define DRWAV_LIST_LABELLED_TEXT_BYTES 20
2056
2057#define DRWAV_METADATA_ALIGNMENT 8
2058
2059typedef enum
2060{
2061 drwav__metadata_parser_stage_count,
2062 drwav__metadata_parser_stage_read
2063} drwav__metadata_parser_stage;
2064
2065typedef struct
2066{
2067 drwav_read_proc onRead;
2068 drwav_seek_proc onSeek;
2069 void *pReadSeekUserData;
2070 drwav__metadata_parser_stage stage;
2071 drwav_metadata *pMetadata;
2072 drwav_uint32 metadataCount;
2073 drwav_uint8 *pData;
2074 drwav_uint8 *pDataCursor;
2075 drwav_uint64 metadataCursor;
2076 drwav_uint64 extraCapacity;
2077} drwav__metadata_parser;
2078
2079DRWAV_PRIVATE size_t drwav__metadata_memory_capacity(drwav__metadata_parser* pParser)
2080{
2081 drwav_uint64 cap = sizeof(drwav_metadata) * (drwav_uint64)pParser->metadataCount + pParser->extraCapacity;
2082 if (cap > DRWAV_SIZE_MAX) {
2083 return 0; /* Too big. */
2084 }
2085
2086 return (size_t)cap; /* Safe cast thanks to the check above. */
2087}
2088
2089DRWAV_PRIVATE drwav_uint8* drwav__metadata_get_memory(drwav__metadata_parser* pParser, size_t size, size_t align)
2090{
2091 drwav_uint8* pResult;
2092
2093 if (align) {
2094 drwav_uintptr modulo = (drwav_uintptr)pParser->pDataCursor % align;
2095 if (modulo != 0) {
2096 pParser->pDataCursor += align - modulo;
2097 }
2098 }
2099
2100 pResult = pParser->pDataCursor;
2101
2102 /*
2103 Getting to the point where this function is called means there should always be memory
2104 available. Out of memory checks should have been done at an earlier stage.
2105 */
2106 DRWAV_ASSERT((pResult + size) <= (pParser->pData + drwav__metadata_memory_capacity(pParser)));
2107
2108 pParser->pDataCursor += size;
2109 return pResult;
2110}
2111
2112DRWAV_PRIVATE void drwav__metadata_request_extra_memory_for_stage_2(drwav__metadata_parser* pParser, size_t bytes, size_t align)
2113{
2114 size_t extra = bytes + (align ? (align - 1) : 0);
2115 pParser->extraCapacity += extra;
2116}
2117
2118DRWAV_PRIVATE drwav_result drwav__metadata_alloc(drwav__metadata_parser* pParser, drwav_allocation_callbacks* pAllocationCallbacks)
2119{
2120 if (pParser->extraCapacity != 0 || pParser->metadataCount != 0) {
2121 pAllocationCallbacks->onFree(pParser->pData, pAllocationCallbacks->pUserData);
2122
2123 pParser->pData = (drwav_uint8*)pAllocationCallbacks->onMalloc(drwav__metadata_memory_capacity(pParser), pAllocationCallbacks->pUserData);
2124 pParser->pDataCursor = pParser->pData;
2125
2126 if (pParser->pData == NULL) {
2127 return DRWAV_OUT_OF_MEMORY;
2128 }
2129
2130 /*
2131 We don't need to worry about specifying an alignment here because malloc always returns something
2132 of suitable alignment. This also means pParser->pMetadata is all that we need to store in order
2133 for us to free when we are done.
2134 */
2135 pParser->pMetadata = (drwav_metadata*)drwav__metadata_get_memory(pParser, sizeof(drwav_metadata) * pParser->metadataCount, 1);
2136 pParser->metadataCursor = 0;
2137 }
2138
2139 return DRWAV_SUCCESS;
2140}
2141
2142DRWAV_PRIVATE size_t drwav__metadata_parser_read(drwav__metadata_parser* pParser, void* pBufferOut, size_t bytesToRead, drwav_uint64* pCursor)
2143{
2144 if (pCursor != NULL) {
2145 return drwav__on_read(pParser->onRead, pParser->pReadSeekUserData, pBufferOut, bytesToRead, pCursor);
2146 } else {
2147 return pParser->onRead(pParser->pReadSeekUserData, pBufferOut, bytesToRead);
2148 }
2149}
2150
2151DRWAV_PRIVATE drwav_uint64 drwav__read_smpl_to_metadata_obj(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_metadata* pMetadata)
2152{
2153 drwav_uint8 smplHeaderData[DRWAV_SMPL_BYTES];
2154 drwav_uint64 totalBytesRead = 0;
2155 size_t bytesJustRead;
2156
2157 if (pMetadata == NULL) {
2158 return 0;
2159 }
2160
2161 bytesJustRead = drwav__metadata_parser_read(pParser, smplHeaderData, sizeof(smplHeaderData), &totalBytesRead);
2162
2163 DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
2164 DRWAV_ASSERT(pChunkHeader != NULL);
2165
2166 if (pMetadata != NULL && bytesJustRead == sizeof(smplHeaderData)) {
2167 drwav_uint32 iSampleLoop;
2168
2169 pMetadata->type = drwav_metadata_type_smpl;
2170 pMetadata->data.smpl.manufacturerId = drwav_bytes_to_u32(smplHeaderData + 0);
2171 pMetadata->data.smpl.productId = drwav_bytes_to_u32(smplHeaderData + 4);
2172 pMetadata->data.smpl.samplePeriodNanoseconds = drwav_bytes_to_u32(smplHeaderData + 8);
2173 pMetadata->data.smpl.midiUnityNote = drwav_bytes_to_u32(smplHeaderData + 12);
2174 pMetadata->data.smpl.midiPitchFraction = drwav_bytes_to_u32(smplHeaderData + 16);
2175 pMetadata->data.smpl.smpteFormat = drwav_bytes_to_u32(smplHeaderData + 20);
2176 pMetadata->data.smpl.smpteOffset = drwav_bytes_to_u32(smplHeaderData + 24);
2177 pMetadata->data.smpl.sampleLoopCount = drwav_bytes_to_u32(smplHeaderData + 28);
2178 pMetadata->data.smpl.samplerSpecificDataSizeInBytes = drwav_bytes_to_u32(smplHeaderData + 32);
2179
2180 /*
2181 The loop count needs to be validated against the size of the chunk for safety so we don't
2182 attempt to read over the boundary of the chunk.
2183 */
2184 if (pMetadata->data.smpl.sampleLoopCount == (pChunkHeader->sizeInBytes - DRWAV_SMPL_BYTES) / DRWAV_SMPL_LOOP_BYTES) {
2185 pMetadata->data.smpl.pLoops = (drwav_smpl_loop*)drwav__metadata_get_memory(pParser, sizeof(drwav_smpl_loop) * pMetadata->data.smpl.sampleLoopCount, DRWAV_METADATA_ALIGNMENT);
2186
2187 for (iSampleLoop = 0; iSampleLoop < pMetadata->data.smpl.sampleLoopCount; ++iSampleLoop) {
2188 drwav_uint8 smplLoopData[DRWAV_SMPL_LOOP_BYTES];
2189 bytesJustRead = drwav__metadata_parser_read(pParser, smplLoopData, sizeof(smplLoopData), &totalBytesRead);
2190
2191 if (bytesJustRead == sizeof(smplLoopData)) {
2192 pMetadata->data.smpl.pLoops[iSampleLoop].cuePointId = drwav_bytes_to_u32(smplLoopData + 0);
2193 pMetadata->data.smpl.pLoops[iSampleLoop].type = drwav_bytes_to_u32(smplLoopData + 4);
2194 pMetadata->data.smpl.pLoops[iSampleLoop].firstSampleByteOffset = drwav_bytes_to_u32(smplLoopData + 8);
2195 pMetadata->data.smpl.pLoops[iSampleLoop].lastSampleByteOffset = drwav_bytes_to_u32(smplLoopData + 12);
2196 pMetadata->data.smpl.pLoops[iSampleLoop].sampleFraction = drwav_bytes_to_u32(smplLoopData + 16);
2197 pMetadata->data.smpl.pLoops[iSampleLoop].playCount = drwav_bytes_to_u32(smplLoopData + 20);
2198 } else {
2199 break;
2200 }
2201 }
2202
2203 if (pMetadata->data.smpl.samplerSpecificDataSizeInBytes > 0) {
2204 pMetadata->data.smpl.pSamplerSpecificData = drwav__metadata_get_memory(pParser, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, 1);
2205 DRWAV_ASSERT(pMetadata->data.smpl.pSamplerSpecificData != NULL);
2206
2207 drwav__metadata_parser_read(pParser, pMetadata->data.smpl.pSamplerSpecificData, pMetadata->data.smpl.samplerSpecificDataSizeInBytes, &totalBytesRead);
2208 }
2209 }
2210 }
2211
2212 return totalBytesRead;
2213}
2214
2215DRWAV_PRIVATE drwav_uint64 drwav__read_cue_to_metadata_obj(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_metadata* pMetadata)
2216{
2217 drwav_uint8 cueHeaderSectionData[DRWAV_CUE_BYTES];
2218 drwav_uint64 totalBytesRead = 0;
2219 size_t bytesJustRead;
2220
2221 if (pMetadata == NULL) {
2222 return 0;
2223 }
2224
2225 bytesJustRead = drwav__metadata_parser_read(pParser, cueHeaderSectionData, sizeof(cueHeaderSectionData), &totalBytesRead);
2226
2227 DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
2228
2229 if (bytesJustRead == sizeof(cueHeaderSectionData)) {
2230 pMetadata->type = drwav_metadata_type_cue;
2231 pMetadata->data.cue.cuePointCount = drwav_bytes_to_u32(cueHeaderSectionData);
2232
2233 /*
2234 We need to validate the cue point count against the size of the chunk so we don't read
2235 beyond the chunk.
2236 */
2237 if (pMetadata->data.cue.cuePointCount == (pChunkHeader->sizeInBytes - DRWAV_CUE_BYTES) / DRWAV_CUE_POINT_BYTES) {
2238 pMetadata->data.cue.pCuePoints = (drwav_cue_point*)drwav__metadata_get_memory(pParser, sizeof(drwav_cue_point) * pMetadata->data.cue.cuePointCount, DRWAV_METADATA_ALIGNMENT);
2239 DRWAV_ASSERT(pMetadata->data.cue.pCuePoints != NULL);
2240
2241 if (pMetadata->data.cue.cuePointCount > 0) {
2242 drwav_uint32 iCuePoint;
2243
2244 for (iCuePoint = 0; iCuePoint < pMetadata->data.cue.cuePointCount; ++iCuePoint) {
2245 drwav_uint8 cuePointData[DRWAV_CUE_POINT_BYTES];
2246 bytesJustRead = drwav__metadata_parser_read(pParser, cuePointData, sizeof(cuePointData), &totalBytesRead);
2247
2248 if (bytesJustRead == sizeof(cuePointData)) {
2249 pMetadata->data.cue.pCuePoints[iCuePoint].id = drwav_bytes_to_u32(cuePointData + 0);
2250 pMetadata->data.cue.pCuePoints[iCuePoint].playOrderPosition = drwav_bytes_to_u32(cuePointData + 4);
2251 pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[0] = cuePointData[8];
2252 pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[1] = cuePointData[9];
2253 pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[2] = cuePointData[10];
2254 pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId[3] = cuePointData[11];
2255 pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart = drwav_bytes_to_u32(cuePointData + 12);
2256 pMetadata->data.cue.pCuePoints[iCuePoint].blockStart = drwav_bytes_to_u32(cuePointData + 16);
2257 pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset = drwav_bytes_to_u32(cuePointData + 20);
2258 } else {
2259 break;
2260 }
2261 }
2262 }
2263 }
2264 }
2265
2266 return totalBytesRead;
2267}
2268
2269DRWAV_PRIVATE drwav_uint64 drwav__read_inst_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata)
2270{
2271 drwav_uint8 instData[DRWAV_INST_BYTES];
2272 drwav_uint64 bytesRead;
2273
2274 if (pMetadata == NULL) {
2275 return 0;
2276 }
2277
2278 bytesRead = drwav__metadata_parser_read(pParser, instData, sizeof(instData), NULL);
2279
2280 DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
2281
2282 if (bytesRead == sizeof(instData)) {
2283 pMetadata->type = drwav_metadata_type_inst;
2284 pMetadata->data.inst.midiUnityNote = (drwav_int8)instData[0];
2285 pMetadata->data.inst.fineTuneCents = (drwav_int8)instData[1];
2286 pMetadata->data.inst.gainDecibels = (drwav_int8)instData[2];
2287 pMetadata->data.inst.lowNote = (drwav_int8)instData[3];
2288 pMetadata->data.inst.highNote = (drwav_int8)instData[4];
2289 pMetadata->data.inst.lowVelocity = (drwav_int8)instData[5];
2290 pMetadata->data.inst.highVelocity = (drwav_int8)instData[6];
2291 }
2292
2293 return bytesRead;
2294}
2295
2296DRWAV_PRIVATE drwav_uint64 drwav__read_acid_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata)
2297{
2298 drwav_uint8 acidData[DRWAV_ACID_BYTES];
2299 drwav_uint64 bytesRead;
2300
2301 if (pMetadata == NULL) {
2302 return 0;
2303 }
2304
2305 bytesRead = drwav__metadata_parser_read(pParser, acidData, sizeof(acidData), NULL);
2306
2307 DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
2308
2309 if (bytesRead == sizeof(acidData)) {
2310 pMetadata->type = drwav_metadata_type_acid;
2311 pMetadata->data.acid.flags = drwav_bytes_to_u32(acidData + 0);
2312 pMetadata->data.acid.midiUnityNote = drwav_bytes_to_u16(acidData + 4);
2313 pMetadata->data.acid.reserved1 = drwav_bytes_to_u16(acidData + 6);
2314 pMetadata->data.acid.reserved2 = drwav_bytes_to_f32(acidData + 8);
2315 pMetadata->data.acid.numBeats = drwav_bytes_to_u32(acidData + 12);
2316 pMetadata->data.acid.meterDenominator = drwav_bytes_to_u16(acidData + 16);
2317 pMetadata->data.acid.meterNumerator = drwav_bytes_to_u16(acidData + 18);
2318 pMetadata->data.acid.tempo = drwav_bytes_to_f32(acidData + 20);
2319 }
2320
2321 return bytesRead;
2322}
2323
2324DRWAV_PRIVATE size_t drwav__strlen(const char* str)
2325{
2326 size_t result = 0;
2327
2328 while (*str++) {
2329 result += 1;
2330 }
2331
2332 return result;
2333}
2334
2335DRWAV_PRIVATE size_t drwav__strlen_clamped(const char* str, size_t maxToRead)
2336{
2337 size_t result = 0;
2338
2339 while (*str++ && result < maxToRead) {
2340 result += 1;
2341 }
2342
2343 return result;
2344}
2345
2346DRWAV_PRIVATE char* drwav__metadata_copy_string(drwav__metadata_parser* pParser, const char* str, size_t maxToRead)
2347{
2348 size_t len = drwav__strlen_clamped(str, maxToRead);
2349
2350 if (len) {
2351 char* result = (char*)drwav__metadata_get_memory(pParser, len + 1, 1);
2352 DRWAV_ASSERT(result != NULL);
2353
2354 DRWAV_COPY_MEMORY(result, str, len);
2355 result[len] = '\0';
2356
2357 return result;
2358 } else {
2359 return NULL;
2360 }
2361}
2362
2363typedef struct
2364{
2365 const void* pBuffer;
2366 size_t sizeInBytes;
2367 size_t cursor;
2368} drwav_buffer_reader;
2369
2370DRWAV_PRIVATE drwav_result drwav_buffer_reader_init(const void* pBuffer, size_t sizeInBytes, drwav_buffer_reader* pReader)
2371{
2372 DRWAV_ASSERT(pBuffer != NULL);
2373 DRWAV_ASSERT(pReader != NULL);
2374
2375 DRWAV_ZERO_OBJECT(pReader);
2376
2377 pReader->pBuffer = pBuffer;
2378 pReader->sizeInBytes = sizeInBytes;
2379 pReader->cursor = 0;
2380
2381 return DRWAV_SUCCESS;
2382}
2383
2384DRWAV_PRIVATE const void* drwav_buffer_reader_ptr(const drwav_buffer_reader* pReader)
2385{
2386 DRWAV_ASSERT(pReader != NULL);
2387
2388 return drwav_offset_ptr(pReader->pBuffer, pReader->cursor);
2389}
2390
2391DRWAV_PRIVATE drwav_result drwav_buffer_reader_seek(drwav_buffer_reader* pReader, size_t bytesToSeek)
2392{
2393 DRWAV_ASSERT(pReader != NULL);
2394
2395 if (pReader->cursor + bytesToSeek > pReader->sizeInBytes) {
2396 return DRWAV_BAD_SEEK; /* Seeking too far forward. */
2397 }
2398
2399 pReader->cursor += bytesToSeek;
2400
2401 return DRWAV_SUCCESS;
2402}
2403
2404DRWAV_PRIVATE drwav_result drwav_buffer_reader_read(drwav_buffer_reader* pReader, void* pDst, size_t bytesToRead, size_t* pBytesRead)
2405{
2406 drwav_result result = DRWAV_SUCCESS;
2407 size_t bytesRemaining;
2408
2409 DRWAV_ASSERT(pReader != NULL);
2410
2411 if (pBytesRead != NULL) {
2412 *pBytesRead = 0;
2413 }
2414
2415 bytesRemaining = (pReader->sizeInBytes - pReader->cursor);
2416 if (bytesToRead > bytesRemaining) {
2417 bytesToRead = bytesRemaining;
2418 }
2419
2420 if (pDst == NULL) {
2421 /* Seek. */
2422 result = drwav_buffer_reader_seek(pReader, bytesToRead);
2423 } else {
2424 /* Read. */
2425 DRWAV_COPY_MEMORY(pDst, drwav_buffer_reader_ptr(pReader), bytesToRead);
2426 pReader->cursor += bytesToRead;
2427 }
2428
2429 DRWAV_ASSERT(pReader->cursor <= pReader->sizeInBytes);
2430
2431 if (result == DRWAV_SUCCESS) {
2432 if (pBytesRead != NULL) {
2433 *pBytesRead = bytesToRead;
2434 }
2435 }
2436
2437 return DRWAV_SUCCESS;
2438}
2439
2440DRWAV_PRIVATE drwav_result drwav_buffer_reader_read_u16(drwav_buffer_reader* pReader, drwav_uint16* pDst)
2441{
2442 drwav_result result;
2443 size_t bytesRead;
2444 drwav_uint8 data[2];
2445
2446 DRWAV_ASSERT(pReader != NULL);
2447 DRWAV_ASSERT(pDst != NULL);
2448
2449 *pDst = 0; /* Safety. */
2450
2451 result = drwav_buffer_reader_read(pReader, data, sizeof(*pDst), &bytesRead);
2452 if (result != DRWAV_SUCCESS || bytesRead != sizeof(*pDst)) {
2453 return result;
2454 }
2455
2456 *pDst = drwav_bytes_to_u16(data);
2457
2458 return DRWAV_SUCCESS;
2459}
2460
2461DRWAV_PRIVATE drwav_result drwav_buffer_reader_read_u32(drwav_buffer_reader* pReader, drwav_uint32* pDst)
2462{
2463 drwav_result result;
2464 size_t bytesRead;
2465 drwav_uint8 data[4];
2466
2467 DRWAV_ASSERT(pReader != NULL);
2468 DRWAV_ASSERT(pDst != NULL);
2469
2470 *pDst = 0; /* Safety. */
2471
2472 result = drwav_buffer_reader_read(pReader, data, sizeof(*pDst), &bytesRead);
2473 if (result != DRWAV_SUCCESS || bytesRead != sizeof(*pDst)) {
2474 return result;
2475 }
2476
2477 *pDst = drwav_bytes_to_u32(data);
2478
2479 return DRWAV_SUCCESS;
2480}
2481
2482
2483
2484DRWAV_PRIVATE drwav_uint64 drwav__read_bext_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata, drwav_uint64 chunkSize)
2485{
2486 drwav_uint8 bextData[DRWAV_BEXT_BYTES];
2487 size_t bytesRead = drwav__metadata_parser_read(pParser, bextData, sizeof(bextData), NULL);
2488
2489 DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
2490
2491 if (bytesRead == sizeof(bextData)) {
2492 drwav_buffer_reader reader;
2493 drwav_uint32 timeReferenceLow;
2494 drwav_uint32 timeReferenceHigh;
2495 size_t extraBytes;
2496
2497 pMetadata->type = drwav_metadata_type_bext;
2498
2499 if (drwav_buffer_reader_init(bextData, bytesRead, &reader) == DRWAV_SUCCESS) {
2500 pMetadata->data.bext.pDescription = drwav__metadata_copy_string(pParser, (const char*)drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_DESCRIPTION_BYTES);
2501 drwav_buffer_reader_seek(&reader, DRWAV_BEXT_DESCRIPTION_BYTES);
2502
2503 pMetadata->data.bext.pOriginatorName = drwav__metadata_copy_string(pParser, (const char*)drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_ORIGINATOR_NAME_BYTES);
2504 drwav_buffer_reader_seek(&reader, DRWAV_BEXT_ORIGINATOR_NAME_BYTES);
2505
2506 pMetadata->data.bext.pOriginatorReference = drwav__metadata_copy_string(pParser, (const char*)drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_ORIGINATOR_REF_BYTES);
2507 drwav_buffer_reader_seek(&reader, DRWAV_BEXT_ORIGINATOR_REF_BYTES);
2508
2509 drwav_buffer_reader_read(&reader, pMetadata->data.bext.pOriginationDate, sizeof(pMetadata->data.bext.pOriginationDate), NULL);
2510 drwav_buffer_reader_read(&reader, pMetadata->data.bext.pOriginationTime, sizeof(pMetadata->data.bext.pOriginationTime), NULL);
2511
2512 drwav_buffer_reader_read_u32(&reader, &timeReferenceLow);
2513 drwav_buffer_reader_read_u32(&reader, &timeReferenceHigh);
2514 pMetadata->data.bext.timeReference = ((drwav_uint64)timeReferenceHigh << 32) + timeReferenceLow;
2515
2516 drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.version);
2517
2518 pMetadata->data.bext.pUMID = drwav__metadata_get_memory(pParser, DRWAV_BEXT_UMID_BYTES, 1);
2519 drwav_buffer_reader_read(&reader, pMetadata->data.bext.pUMID, DRWAV_BEXT_UMID_BYTES, NULL);
2520
2521 drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.loudnessValue);
2522 drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.loudnessRange);
2523 drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxTruePeakLevel);
2524 drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxMomentaryLoudness);
2525 drwav_buffer_reader_read_u16(&reader, &pMetadata->data.bext.maxShortTermLoudness);
2526
2527 DRWAV_ASSERT((drwav_offset_ptr(drwav_buffer_reader_ptr(&reader), DRWAV_BEXT_RESERVED_BYTES)) == (bextData + DRWAV_BEXT_BYTES));
2528
2529 extraBytes = (size_t)(chunkSize - DRWAV_BEXT_BYTES);
2530 if (extraBytes > 0) {
2531 pMetadata->data.bext.pCodingHistory = (char*)drwav__metadata_get_memory(pParser, extraBytes + 1, 1);
2532 DRWAV_ASSERT(pMetadata->data.bext.pCodingHistory != NULL);
2533
2534 bytesRead += drwav__metadata_parser_read(pParser, pMetadata->data.bext.pCodingHistory, extraBytes, NULL);
2535 pMetadata->data.bext.codingHistorySize = (drwav_uint32)drwav__strlen(pMetadata->data.bext.pCodingHistory);
2536 } else {
2537 pMetadata->data.bext.pCodingHistory = NULL;
2538 pMetadata->data.bext.codingHistorySize = 0;
2539 }
2540 }
2541 }
2542
2543 return bytesRead;
2544}
2545
2546DRWAV_PRIVATE drwav_uint64 drwav__read_list_label_or_note_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata, drwav_uint64 chunkSize, drwav_metadata_type type)
2547{
2548 drwav_uint8 cueIDBuffer[DRWAV_LIST_LABEL_OR_NOTE_BYTES];
2549 drwav_uint64 totalBytesRead = 0;
2550 size_t bytesJustRead = drwav__metadata_parser_read(pParser, cueIDBuffer, sizeof(cueIDBuffer), &totalBytesRead);
2551
2552 DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
2553
2554 if (bytesJustRead == sizeof(cueIDBuffer)) {
2555 drwav_uint32 sizeIncludingNullTerminator;
2556
2557 pMetadata->type = type;
2558 pMetadata->data.labelOrNote.cuePointId = drwav_bytes_to_u32(cueIDBuffer);
2559
2560 sizeIncludingNullTerminator = (drwav_uint32)chunkSize - DRWAV_LIST_LABEL_OR_NOTE_BYTES;
2561 if (sizeIncludingNullTerminator > 0) {
2562 pMetadata->data.labelOrNote.stringLength = sizeIncludingNullTerminator - 1;
2563 pMetadata->data.labelOrNote.pString = (char*)drwav__metadata_get_memory(pParser, sizeIncludingNullTerminator, 1);
2564 DRWAV_ASSERT(pMetadata->data.labelOrNote.pString != NULL);
2565
2566 drwav__metadata_parser_read(pParser, pMetadata->data.labelOrNote.pString, sizeIncludingNullTerminator, &totalBytesRead);
2567 } else {
2568 pMetadata->data.labelOrNote.stringLength = 0;
2569 pMetadata->data.labelOrNote.pString = NULL;
2570 }
2571 }
2572
2573 return totalBytesRead;
2574}
2575
2576DRWAV_PRIVATE drwav_uint64 drwav__read_list_labelled_cue_region_to_metadata_obj(drwav__metadata_parser* pParser, drwav_metadata* pMetadata, drwav_uint64 chunkSize)
2577{
2578 drwav_uint8 buffer[DRWAV_LIST_LABELLED_TEXT_BYTES];
2579 drwav_uint64 totalBytesRead = 0;
2580 size_t bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &totalBytesRead);
2581
2582 DRWAV_ASSERT(pParser->stage == drwav__metadata_parser_stage_read);
2583
2584 if (bytesJustRead == sizeof(buffer)) {
2585 drwav_uint32 sizeIncludingNullTerminator;
2586
2587 pMetadata->type = drwav_metadata_type_list_labelled_cue_region;
2588 pMetadata->data.labelledCueRegion.cuePointId = drwav_bytes_to_u32(buffer + 0);
2589 pMetadata->data.labelledCueRegion.sampleLength = drwav_bytes_to_u32(buffer + 4);
2590 pMetadata->data.labelledCueRegion.purposeId[0] = buffer[8];
2591 pMetadata->data.labelledCueRegion.purposeId[1] = buffer[9];
2592 pMetadata->data.labelledCueRegion.purposeId[2] = buffer[10];
2593 pMetadata->data.labelledCueRegion.purposeId[3] = buffer[11];
2594 pMetadata->data.labelledCueRegion.country = drwav_bytes_to_u16(buffer + 12);
2595 pMetadata->data.labelledCueRegion.language = drwav_bytes_to_u16(buffer + 14);
2596 pMetadata->data.labelledCueRegion.dialect = drwav_bytes_to_u16(buffer + 16);
2597 pMetadata->data.labelledCueRegion.codePage = drwav_bytes_to_u16(buffer + 18);
2598
2599 sizeIncludingNullTerminator = (drwav_uint32)chunkSize - DRWAV_LIST_LABELLED_TEXT_BYTES;
2600 if (sizeIncludingNullTerminator > 0) {
2601 pMetadata->data.labelledCueRegion.stringLength = sizeIncludingNullTerminator - 1;
2602 pMetadata->data.labelledCueRegion.pString = (char*)drwav__metadata_get_memory(pParser, sizeIncludingNullTerminator, 1);
2603 DRWAV_ASSERT(pMetadata->data.labelledCueRegion.pString != NULL);
2604
2605 drwav__metadata_parser_read(pParser, pMetadata->data.labelledCueRegion.pString, sizeIncludingNullTerminator, &totalBytesRead);
2606 } else {
2607 pMetadata->data.labelledCueRegion.stringLength = 0;
2608 pMetadata->data.labelledCueRegion.pString = NULL;
2609 }
2610 }
2611
2612 return totalBytesRead;
2613}
2614
2615DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_info_text_chunk(drwav__metadata_parser* pParser, drwav_uint64 chunkSize, drwav_metadata_type type)
2616{
2617 drwav_uint64 bytesRead = 0;
2618 drwav_uint32 stringSizeWithNullTerminator = (drwav_uint32)chunkSize;
2619
2620 if (pParser->stage == drwav__metadata_parser_stage_count) {
2621 pParser->metadataCount += 1;
2622 drwav__metadata_request_extra_memory_for_stage_2(pParser, stringSizeWithNullTerminator, 1);
2623 } else {
2624 drwav_metadata* pMetadata = &pParser->pMetadata[pParser->metadataCursor];
2625 pMetadata->type = type;
2626 if (stringSizeWithNullTerminator > 0) {
2627 pMetadata->data.infoText.stringLength = stringSizeWithNullTerminator - 1;
2628 pMetadata->data.infoText.pString = (char*)drwav__metadata_get_memory(pParser, stringSizeWithNullTerminator, 1);
2629 DRWAV_ASSERT(pMetadata->data.infoText.pString != NULL);
2630
2631 bytesRead = drwav__metadata_parser_read(pParser, pMetadata->data.infoText.pString, (size_t)stringSizeWithNullTerminator, NULL);
2632 if (bytesRead == chunkSize) {
2633 pParser->metadataCursor += 1;
2634 } else {
2635 /* Failed to parse. */
2636 }
2637 } else {
2638 pMetadata->data.infoText.stringLength = 0;
2639 pMetadata->data.infoText.pString = NULL;
2640 pParser->metadataCursor += 1;
2641 }
2642 }
2643
2644 return bytesRead;
2645}
2646
2647DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_unknown_chunk(drwav__metadata_parser* pParser, const drwav_uint8* pChunkId, drwav_uint64 chunkSize, drwav_metadata_location location)
2648{
2649 drwav_uint64 bytesRead = 0;
2650
2651 if (location == drwav_metadata_location_invalid) {
2652 return 0;
2653 }
2654
2655 if (drwav_fourcc_equal(pChunkId, "data") || drwav_fourcc_equal(pChunkId, "fmt ") || drwav_fourcc_equal(pChunkId, "fact")) {
2656 return 0;
2657 }
2658
2659 if (pParser->stage == drwav__metadata_parser_stage_count) {
2660 pParser->metadataCount += 1;
2661 drwav__metadata_request_extra_memory_for_stage_2(pParser, (size_t)chunkSize, 1);
2662 } else {
2663 drwav_metadata* pMetadata = &pParser->pMetadata[pParser->metadataCursor];
2664 pMetadata->type = drwav_metadata_type_unknown;
2665 pMetadata->data.unknown.chunkLocation = location;
2666 pMetadata->data.unknown.id[0] = pChunkId[0];
2667 pMetadata->data.unknown.id[1] = pChunkId[1];
2668 pMetadata->data.unknown.id[2] = pChunkId[2];
2669 pMetadata->data.unknown.id[3] = pChunkId[3];
2670 pMetadata->data.unknown.dataSizeInBytes = (drwav_uint32)chunkSize;
2671 pMetadata->data.unknown.pData = (drwav_uint8 *)drwav__metadata_get_memory(pParser, (size_t)chunkSize, 1);
2672 DRWAV_ASSERT(pMetadata->data.unknown.pData != NULL);
2673
2674 bytesRead = drwav__metadata_parser_read(pParser, pMetadata->data.unknown.pData, pMetadata->data.unknown.dataSizeInBytes, NULL);
2675 if (bytesRead == pMetadata->data.unknown.dataSizeInBytes) {
2676 pParser->metadataCursor += 1;
2677 } else {
2678 /* Failed to read. */
2679 }
2680 }
2681
2682 return bytesRead;
2683}
2684
2685DRWAV_PRIVATE drwav_bool32 drwav__chunk_matches(drwav_metadata_type allowedMetadataTypes, const drwav_uint8* pChunkID, drwav_metadata_type type, const char* pID)
2686{
2687 return (allowedMetadataTypes & type) && drwav_fourcc_equal(pChunkID, pID);
2688}
2689
2690DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser* pParser, const drwav_chunk_header* pChunkHeader, drwav_metadata_type allowedMetadataTypes)
2691{
2692 const drwav_uint8 *pChunkID = pChunkHeader->id.fourcc;
2693 drwav_uint64 bytesRead = 0;
2694
2695 if (drwav__chunk_matches(allowedMetadataTypes, pChunkID, drwav_metadata_type_smpl, "smpl")) {
2696 if (pChunkHeader->sizeInBytes >= DRWAV_SMPL_BYTES) {
2697 if (pParser->stage == drwav__metadata_parser_stage_count) {
2698 drwav_uint8 buffer[4];
2699 size_t bytesJustRead;
2700
2701 if (!pParser->onSeek(pParser->pReadSeekUserData, 28, drwav_seek_origin_current)) {
2702 return bytesRead;
2703 }
2704 bytesRead += 28;
2705
2706 bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead);
2707 if (bytesJustRead == sizeof(buffer)) {
2708 drwav_uint32 loopCount = drwav_bytes_to_u32(buffer);
2709 drwav_uint64 calculatedLoopCount;
2710
2711 /* The loop count must be validated against the size of the chunk. */
2712 calculatedLoopCount = (pChunkHeader->sizeInBytes - DRWAV_SMPL_BYTES) / DRWAV_SMPL_LOOP_BYTES;
2713 if (calculatedLoopCount == loopCount) {
2714 bytesJustRead = drwav__metadata_parser_read(pParser, buffer, sizeof(buffer), &bytesRead);
2715 if (bytesJustRead == sizeof(buffer)) {
2716 drwav_uint32 samplerSpecificDataSizeInBytes = drwav_bytes_to_u32(buffer);
2717
2718 pParser->metadataCount += 1;
2719 drwav__metadata_request_extra_memory_for_stage_2(pParser, sizeof(drwav_smpl_loop) * loopCount, DRWAV_METADATA_ALIGNMENT);
2720 drwav__metadata_request_extra_memory_for_stage_2(pParser, samplerSpecificDataSizeInBytes, 1);
2721 }
2722 } else {
2723 /* Loop count in header does not match the size of the chunk. */
2724 }
2725 }
2726 } else {
2727 bytesRead = drwav__read_smpl_to_metadata_obj(pParser, pChunkHeader, &pParser->pMetadata[pParser->metadataCursor]);
2728 if (bytesRead == pChunkHeader->sizeInBytes) {
2729 pParser->metadataCursor += 1;
2730 } else {
2731 /* Failed to parse. */
2732 }
2733 }
2734 } else {
2735 /* Incorrectly formed chunk. */
2736 }
2737 } else if (drwav__chunk_matches(allowedMetadataTypes, pChunkID, drwav_metadata_type_inst, "inst")) {
2738 if (pChunkHeader->sizeInBytes == DRWAV_INST_BYTES) {
2739 if (pParser->stage == drwav__metadata_parser_stage_count) {
2740 pParser->metadataCount += 1;
2741 } else {
2742 bytesRead = drwav__read_inst_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor]);
2743 if (bytesRead == pChunkHeader->sizeInBytes) {
2744 pParser->metadataCursor += 1;
2745 } else {
2746 /* Failed to parse. */
2747 }
2748 }
2749 } else {
2750 /* Incorrectly formed chunk. */
2751 }
2752 } else if (drwav__chunk_matches(allowedMetadataTypes, pChunkID, drwav_metadata_type_acid, "acid")) {
2753 if (pChunkHeader->sizeInBytes == DRWAV_ACID_BYTES) {
2754 if (pParser->stage == drwav__metadata_parser_stage_count) {
2755 pParser->metadataCount += 1;
2756 } else {
2757 bytesRead = drwav__read_acid_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor]);
2758 if (bytesRead == pChunkHeader->sizeInBytes) {
2759 pParser->metadataCursor += 1;
2760 } else {
2761 /* Failed to parse. */
2762 }
2763 }
2764 } else {
2765 /* Incorrectly formed chunk. */
2766 }
2767 } else if (drwav__chunk_matches(allowedMetadataTypes, pChunkID, drwav_metadata_type_cue, "cue ")) {
2768 if (pChunkHeader->sizeInBytes >= DRWAV_CUE_BYTES) {
2769 if (pParser->stage == drwav__metadata_parser_stage_count) {
2770 size_t cueCount;
2771
2772 pParser->metadataCount += 1;
2773 cueCount = (size_t)(pChunkHeader->sizeInBytes - DRWAV_CUE_BYTES) / DRWAV_CUE_POINT_BYTES;
2774 drwav__metadata_request_extra_memory_for_stage_2(pParser, sizeof(drwav_cue_point) * cueCount, DRWAV_METADATA_ALIGNMENT);
2775 } else {
2776 bytesRead = drwav__read_cue_to_metadata_obj(pParser, pChunkHeader, &pParser->pMetadata[pParser->metadataCursor]);
2777 if (bytesRead == pChunkHeader->sizeInBytes) {
2778 pParser->metadataCursor += 1;
2779 } else {
2780 /* Failed to parse. */
2781 }
2782 }
2783 } else {
2784 /* Incorrectly formed chunk. */
2785 }
2786 } else if (drwav__chunk_matches(allowedMetadataTypes, pChunkID, drwav_metadata_type_bext, "bext")) {
2787 if (pChunkHeader->sizeInBytes >= DRWAV_BEXT_BYTES) {
2788 if (pParser->stage == drwav__metadata_parser_stage_count) {
2789 /* The description field is the largest one in a bext chunk, so that is the max size of this temporary buffer. */
2790 char buffer[DRWAV_BEXT_DESCRIPTION_BYTES + 1];
2791 size_t allocSizeNeeded = DRWAV_BEXT_UMID_BYTES; /* We know we will need SMPTE umid size. */
2792 size_t bytesJustRead;
2793
2794 buffer[DRWAV_BEXT_DESCRIPTION_BYTES] = '\0';
2795 bytesJustRead = drwav__metadata_parser_read(pParser, buffer, DRWAV_BEXT_DESCRIPTION_BYTES, &bytesRead);
2796 if (bytesJustRead != DRWAV_BEXT_DESCRIPTION_BYTES) {
2797 return bytesRead;
2798 }
2799 allocSizeNeeded += drwav__strlen(buffer) + 1;
2800
2801 buffer[DRWAV_BEXT_ORIGINATOR_NAME_BYTES] = '\0';
2802 bytesJustRead = drwav__metadata_parser_read(pParser, buffer, DRWAV_BEXT_ORIGINATOR_NAME_BYTES, &bytesRead);
2803 if (bytesJustRead != DRWAV_BEXT_ORIGINATOR_NAME_BYTES) {
2804 return bytesRead;
2805 }
2806 allocSizeNeeded += drwav__strlen(buffer) + 1;
2807
2808 buffer[DRWAV_BEXT_ORIGINATOR_REF_BYTES] = '\0';
2809 bytesJustRead = drwav__metadata_parser_read(pParser, buffer, DRWAV_BEXT_ORIGINATOR_REF_BYTES, &bytesRead);
2810 if (bytesJustRead != DRWAV_BEXT_ORIGINATOR_REF_BYTES) {
2811 return bytesRead;
2812 }
2813 allocSizeNeeded += drwav__strlen(buffer) + 1;
2814 allocSizeNeeded += (size_t)pChunkHeader->sizeInBytes - DRWAV_BEXT_BYTES; /* Coding history. */
2815
2816 drwav__metadata_request_extra_memory_for_stage_2(pParser, allocSizeNeeded, 1);
2817
2818 pParser->metadataCount += 1;
2819 } else {
2820 bytesRead = drwav__read_bext_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor], pChunkHeader->sizeInBytes);
2821 if (bytesRead == pChunkHeader->sizeInBytes) {
2822 pParser->metadataCursor += 1;
2823 } else {
2824 /* Failed to parse. */
2825 }
2826 }
2827 } else {
2828 /* Incorrectly formed chunk. */
2829 }
2830 } else if (drwav_fourcc_equal(pChunkID, "LIST") || drwav_fourcc_equal(pChunkID, "list")) {
2831 drwav_metadata_location listType = drwav_metadata_location_invalid;
2832 while (bytesRead < pChunkHeader->sizeInBytes) {
2833 drwav_uint8 subchunkId[4];
2834 drwav_uint8 subchunkSizeBuffer[4];
2835 drwav_uint64 subchunkDataSize;
2836 drwav_uint64 subchunkBytesRead = 0;
2837 drwav_uint64 bytesJustRead = drwav__metadata_parser_read(pParser, subchunkId, sizeof(subchunkId), &bytesRead);
2838 if (bytesJustRead != sizeof(subchunkId)) {
2839 break;
2840 }
2841
2842 /*
2843 The first thing in a list chunk should be "adtl" or "INFO".
2844
2845 - adtl means this list is a Associated Data List Chunk and will contain labels, notes
2846 or labelled cue regions.
2847 - INFO means this list is an Info List Chunk containing info text chunks such as IPRD
2848 which would specifies the album of this wav file.
2849
2850 No data follows the adtl or INFO id so we just make note of what type this list is and
2851 continue.
2852 */
2853 if (drwav_fourcc_equal(subchunkId, "adtl")) {
2854 listType = drwav_metadata_location_inside_adtl_list;
2855 continue;
2856 } else if (drwav_fourcc_equal(subchunkId, "INFO")) {
2857 listType = drwav_metadata_location_inside_info_list;
2858 continue;
2859 }
2860
2861 bytesJustRead = drwav__metadata_parser_read(pParser, subchunkSizeBuffer, sizeof(subchunkSizeBuffer), &bytesRead);
2862 if (bytesJustRead != sizeof(subchunkSizeBuffer)) {
2863 break;
2864 }
2865 subchunkDataSize = drwav_bytes_to_u32(subchunkSizeBuffer);
2866
2867 if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_label, "labl") || drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_note, "note")) {
2868 if (subchunkDataSize >= DRWAV_LIST_LABEL_OR_NOTE_BYTES) {
2869 drwav_uint64 stringSizeWithNullTerm = subchunkDataSize - DRWAV_LIST_LABEL_OR_NOTE_BYTES;
2870 if (pParser->stage == drwav__metadata_parser_stage_count) {
2871 pParser->metadataCount += 1;
2872 drwav__metadata_request_extra_memory_for_stage_2(pParser, (size_t)stringSizeWithNullTerm, 1);
2873 } else {
2874 subchunkBytesRead = drwav__read_list_label_or_note_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor], subchunkDataSize, drwav_fourcc_equal(subchunkId, "labl") ? drwav_metadata_type_list_label : drwav_metadata_type_list_note);
2875 if (subchunkBytesRead == subchunkDataSize) {
2876 pParser->metadataCursor += 1;
2877 } else {
2878 /* Failed to parse. */
2879 }
2880 }
2881 } else {
2882 /* Incorrectly formed chunk. */
2883 }
2884 } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_labelled_cue_region, "ltxt")) {
2885 if (subchunkDataSize >= DRWAV_LIST_LABELLED_TEXT_BYTES) {
2886 drwav_uint64 stringSizeWithNullTerminator = subchunkDataSize - DRWAV_LIST_LABELLED_TEXT_BYTES;
2887 if (pParser->stage == drwav__metadata_parser_stage_count) {
2888 pParser->metadataCount += 1;
2889 drwav__metadata_request_extra_memory_for_stage_2(pParser, (size_t)stringSizeWithNullTerminator, 1);
2890 } else {
2891 subchunkBytesRead = drwav__read_list_labelled_cue_region_to_metadata_obj(pParser, &pParser->pMetadata[pParser->metadataCursor], subchunkDataSize);
2892 if (subchunkBytesRead == subchunkDataSize) {
2893 pParser->metadataCursor += 1;
2894 } else {
2895 /* Failed to parse. */
2896 }
2897 }
2898 } else {
2899 /* Incorrectly formed chunk. */
2900 }
2901 } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_software, "ISFT")) {
2902 subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_software);
2903 } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_copyright, "ICOP")) {
2904 subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_copyright);
2905 } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_title, "INAM")) {
2906 subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_title);
2907 } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_artist, "IART")) {
2908 subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_artist);
2909 } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_comment, "ICMT")) {
2910 subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_comment);
2911 } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_date, "ICRD")) {
2912 subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_date);
2913 } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_genre, "IGNR")) {
2914 subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_genre);
2915 } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_album, "IPRD")) {
2916 subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_album);
2917 } else if (drwav__chunk_matches(allowedMetadataTypes, subchunkId, drwav_metadata_type_list_info_tracknumber, "ITRK")) {
2918 subchunkBytesRead = drwav__metadata_process_info_text_chunk(pParser, subchunkDataSize, drwav_metadata_type_list_info_tracknumber);
2919 } else if ((allowedMetadataTypes & drwav_metadata_type_unknown) != 0) {
2920 subchunkBytesRead = drwav__metadata_process_unknown_chunk(pParser, subchunkId, subchunkDataSize, listType);
2921 }
2922
2923 bytesRead += subchunkBytesRead;
2924 DRWAV_ASSERT(subchunkBytesRead <= subchunkDataSize);
2925
2926 if (subchunkBytesRead < subchunkDataSize) {
2927 drwav_uint64 bytesToSeek = subchunkDataSize - subchunkBytesRead;
2928
2929 if (!pParser->onSeek(pParser->pReadSeekUserData, (int)bytesToSeek, drwav_seek_origin_current)) {
2930 break;
2931 }
2932 bytesRead += bytesToSeek;
2933 }
2934
2935 if ((subchunkDataSize % 2) == 1) {
2936 if (!pParser->onSeek(pParser->pReadSeekUserData, 1, drwav_seek_origin_current)) {
2937 break;
2938 }
2939 bytesRead += 1;
2940 }
2941 }
2942 } else if ((allowedMetadataTypes & drwav_metadata_type_unknown) != 0) {
2943 bytesRead = drwav__metadata_process_unknown_chunk(pParser, pChunkID, pChunkHeader->sizeInBytes, drwav_metadata_location_top_level);
2944 }
2945
2946 return bytesRead;
2947}
2948
2949
2950DRWAV_PRIVATE drwav_uint32 drwav_get_bytes_per_pcm_frame(drwav* pWav)
2951{
2952 drwav_uint32 bytesPerFrame;
2953
2954 /*
2955 The bytes per frame is a bit ambiguous. It can be either be based on the bits per sample, or the block align. The way I'm doing it here
2956 is that if the bits per sample is a multiple of 8, use floor(bitsPerSample*channels/8), otherwise fall back to the block align.
2957 */
2958 if ((pWav->bitsPerSample & 0x7) == 0) {
2959 /* Bits per sample is a multiple of 8. */
2960 bytesPerFrame = (pWav->bitsPerSample * pWav->fmt.channels) >> 3;
2961 } else {
2962 bytesPerFrame = pWav->fmt.blockAlign;
2963 }
2964
2965 /* Validation for known formats. a-law and mu-law should be 1 byte per channel. If it's not, it's not decodable. */
2966 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW || pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
2967 if (bytesPerFrame != pWav->fmt.channels) {
2968 return 0; /* Invalid file. */
2969 }
2970 }
2971
2972 return bytesPerFrame;
2973}
2974
2975DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT)
2976{
2977 if (pFMT == NULL) {
2978 return 0;
2979 }
2980
2981 if (pFMT->formatTag != DR_WAVE_FORMAT_EXTENSIBLE) {
2982 return pFMT->formatTag;
2983 } else {
2984 return drwav_bytes_to_u16(pFMT->subFormat); /* Only the first two bytes are required. */
2985 }
2986}
2987
2988DRWAV_PRIVATE drwav_bool32 drwav_preinit(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pReadSeekUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
2989{
2990 if (pWav == NULL || onRead == NULL || onSeek == NULL) {
2991 return DRWAV_FALSE;
2992 }
2993
2994 DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav));
2995 pWav->onRead = onRead;
2996 pWav->onSeek = onSeek;
2997 pWav->pUserData = pReadSeekUserData;
2998 pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks);
2999
3000 if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) {
3001 return DRWAV_FALSE; /* Invalid allocation callbacks. */
3002 }
3003
3004 return DRWAV_TRUE;
3005}
3006
3007DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags)
3008{
3009 /* This function assumes drwav_preinit() has been called beforehand. */
3010 drwav_result result;
3011 drwav_uint64 cursor; /* <-- Keeps track of the byte position so we can seek to specific locations. */
3012 drwav_bool32 sequential;
3013 drwav_uint8 riff[4];
3014 drwav_fmt fmt;
3015 unsigned short translatedFormatTag;
3016 drwav_uint64 dataChunkSize = 0; /* <-- Important! Don't explicitly set this to 0 anywhere else. Calculation of the size of the data chunk is performed in different paths depending on the container. */
3017 drwav_uint64 sampleCountFromFactChunk = 0; /* Same as dataChunkSize - make sure this is the only place this is initialized to 0. */
3018 drwav_uint64 metadataStartPos;
3019 drwav__metadata_parser metadataParser;
3020 drwav_bool8 isProcessingMetadata = DRWAV_FALSE;
3021 drwav_bool8 foundChunk_fmt = DRWAV_FALSE;
3022 drwav_bool8 foundChunk_data = DRWAV_FALSE;
3023 drwav_bool8 isAIFCFormType = DRWAV_FALSE; /* Only used with AIFF. */
3024 drwav_uint64 aiffFrameCount = 0;
3025
3026 cursor = 0;
3027 sequential = (flags & DRWAV_SEQUENTIAL) != 0;
3028 DRWAV_ZERO_OBJECT(&fmt);
3029
3030 /* The first 4 bytes should be the RIFF identifier. */
3031 if (drwav__on_read(pWav->onRead, pWav->pUserData, riff, sizeof(riff), &cursor) != sizeof(riff)) {
3032 return DRWAV_FALSE;
3033 }
3034
3035 /*
3036 The first 4 bytes can be used to identify the container. For RIFF files it will start with "RIFF" and for
3037 w64 it will start with "riff".
3038 */
3039 if (drwav_fourcc_equal(riff, "RIFF")) {
3040 pWav->container = drwav_container_riff;
3041 } else if (drwav_fourcc_equal(riff, "RIFX")) {
3042 pWav->container = drwav_container_rifx;
3043 } else if (drwav_fourcc_equal(riff, "riff")) {
3044 int i;
3045 drwav_uint8 riff2[12];
3046
3047 pWav->container = drwav_container_w64;
3048
3049 /* Check the rest of the GUID for validity. */
3050 if (drwav__on_read(pWav->onRead, pWav->pUserData, riff2, sizeof(riff2), &cursor) != sizeof(riff2)) {
3051 return DRWAV_FALSE;
3052 }
3053
3054 for (i = 0; i < 12; ++i) {
3055 if (riff2[i] != drwavGUID_W64_RIFF[i+4]) {
3056 return DRWAV_FALSE;
3057 }
3058 }
3059 } else if (drwav_fourcc_equal(riff, "RF64")) {
3060 pWav->container = drwav_container_rf64;
3061 } else if (drwav_fourcc_equal(riff, "FORM")) {
3062 pWav->container = drwav_container_aiff;
3063 } else {
3064 return DRWAV_FALSE; /* Unknown or unsupported container. */
3065 }
3066
3067
3068 if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rifx || pWav->container == drwav_container_rf64) {
3069 drwav_uint8 chunkSizeBytes[4];
3070 drwav_uint8 wave[4];
3071
3072 if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) {
3073 return DRWAV_FALSE;
3074 }
3075
3076 if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rifx) {
3077 if (drwav_bytes_to_u32_ex(chunkSizeBytes, pWav->container) < 36) {
3078 /*
3079 I've had a report of a WAV file failing to load when the size of the WAVE chunk is not encoded
3080 and is instead just set to 0. I'm going to relax the validation here to allow these files to
3081 load. Considering the chunk size isn't actually used this should be safe. With this change my
3082 test suite still passes.
3083 */
3084 /*return DRWAV_FALSE;*/ /* Chunk size should always be at least 36 bytes. */
3085 }
3086 } else if (pWav->container == drwav_container_rf64) {
3087 if (drwav_bytes_to_u32_le(chunkSizeBytes) != 0xFFFFFFFF) {
3088 return DRWAV_FALSE; /* Chunk size should always be set to -1/0xFFFFFFFF for RF64. The actual size is retrieved later. */
3089 }
3090 } else {
3091 return DRWAV_FALSE; /* Should never hit this. */
3092 }
3093
3094 if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) {
3095 return DRWAV_FALSE;
3096 }
3097
3098 if (!drwav_fourcc_equal(wave, "WAVE")) {
3099 return DRWAV_FALSE; /* Expecting "WAVE". */
3100 }
3101 } else if (pWav->container == drwav_container_w64) {
3102 drwav_uint8 chunkSizeBytes[8];
3103 drwav_uint8 wave[16];
3104
3105 if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) {
3106 return DRWAV_FALSE;
3107 }
3108
3109 if (drwav_bytes_to_u64(chunkSizeBytes) < 80) {
3110 return DRWAV_FALSE;
3111 }
3112
3113 if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) {
3114 return DRWAV_FALSE;
3115 }
3116
3117 if (!drwav_guid_equal(wave, drwavGUID_W64_WAVE)) {
3118 return DRWAV_FALSE;
3119 }
3120 } else if (pWav->container == drwav_container_aiff) {
3121 drwav_uint8 chunkSizeBytes[4];
3122 drwav_uint8 aiff[4];
3123
3124 if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) {
3125 return DRWAV_FALSE;
3126 }
3127
3128 if (drwav_bytes_to_u32_be(chunkSizeBytes) < 18) {
3129 return DRWAV_FALSE;
3130 }
3131
3132 if (drwav__on_read(pWav->onRead, pWav->pUserData, aiff, sizeof(aiff), &cursor) != sizeof(aiff)) {
3133 return DRWAV_FALSE;
3134 }
3135
3136 if (drwav_fourcc_equal(aiff, "AIFF")) {
3137 isAIFCFormType = DRWAV_FALSE;
3138 } else if (drwav_fourcc_equal(aiff, "AIFC")) {
3139 isAIFCFormType = DRWAV_TRUE;
3140 } else {
3141 return DRWAV_FALSE; /* Expecting "AIFF" or "AIFC". */
3142 }
3143 } else {
3144 return DRWAV_FALSE;
3145 }
3146
3147
3148 /* For RF64, the "ds64" chunk must come next, before the "fmt " chunk. */
3149 if (pWav->container == drwav_container_rf64) {
3150 drwav_uint8 sizeBytes[8];
3151 drwav_uint64 bytesRemainingInChunk;
3152 drwav_chunk_header header;
3153 result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header);
3154 if (result != DRWAV_SUCCESS) {
3155 return DRWAV_FALSE;
3156 }
3157
3158 if (!drwav_fourcc_equal(header.id.fourcc, "ds64")) {
3159 return DRWAV_FALSE; /* Expecting "ds64". */
3160 }
3161
3162 bytesRemainingInChunk = header.sizeInBytes + header.paddingSize;
3163
3164 /* We don't care about the size of the RIFF chunk - skip it. */
3165 if (!drwav__seek_forward(pWav->onSeek, 8, pWav->pUserData)) {
3166 return DRWAV_FALSE;
3167 }
3168 bytesRemainingInChunk -= 8;
3169 cursor += 8;
3170
3171
3172 /* Next 8 bytes is the size of the "data" chunk. */
3173 if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) {
3174 return DRWAV_FALSE;
3175 }
3176 bytesRemainingInChunk -= 8;
3177 dataChunkSize = drwav_bytes_to_u64(sizeBytes);
3178
3179
3180 /* Next 8 bytes is the same count which we would usually derived from the FACT chunk if it was available. */
3181 if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) {
3182 return DRWAV_FALSE;
3183 }
3184 bytesRemainingInChunk -= 8;
3185 sampleCountFromFactChunk = drwav_bytes_to_u64(sizeBytes);
3186
3187
3188 /* Skip over everything else. */
3189 if (!drwav__seek_forward(pWav->onSeek, bytesRemainingInChunk, pWav->pUserData)) {
3190 return DRWAV_FALSE;
3191 }
3192 cursor += bytesRemainingInChunk;
3193 }
3194
3195
3196 metadataStartPos = cursor;
3197
3198 /*
3199 Whether or not we are processing metadata controls how we load. We can load more efficiently when
3200 metadata is not being processed, but we also cannot process metadata for Wave64 because I have not
3201 been able to test it. If someone is able to test this and provide a patch I'm happy to enable it.
3202
3203 Seqential mode cannot support metadata because it involves seeking backwards.
3204 */
3205 isProcessingMetadata = !sequential && ((flags & DRWAV_WITH_METADATA) != 0);
3206
3207 /* Don't allow processing of metadata with untested containers. */
3208 if (pWav->container != drwav_container_riff && pWav->container != drwav_container_rf64) {
3209 isProcessingMetadata = DRWAV_FALSE;
3210 }
3211
3212 DRWAV_ZERO_MEMORY(&metadataParser, sizeof(metadataParser));
3213 if (isProcessingMetadata) {
3214 metadataParser.onRead = pWav->onRead;
3215 metadataParser.onSeek = pWav->onSeek;
3216 metadataParser.pReadSeekUserData = pWav->pUserData;
3217 metadataParser.stage = drwav__metadata_parser_stage_count;
3218 }
3219
3220
3221 /*
3222 From here on out, chunks might be in any order. In order to robustly handle metadata we'll need
3223 to loop through every chunk and handle them as we find them. In sequential mode we need to get
3224 out of the loop as soon as we find the data chunk because we won't be able to seek back.
3225 */
3226 for (;;) { /* For each chunk... */
3227 drwav_chunk_header header;
3228 drwav_uint64 chunkSize;
3229
3230 result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header);
3231 if (result != DRWAV_SUCCESS) {
3232 break;
3233 }
3234
3235 chunkSize = header.sizeInBytes;
3236
3237
3238 /*
3239 Always tell the caller about this chunk. We cannot do this in sequential mode because the
3240 callback is allowed to read from the file, in which case we'll need to rewind.
3241 */
3242 if (!sequential && onChunk != NULL) {
3243 drwav_uint64 callbackBytesRead = onChunk(pChunkUserData, pWav->onRead, pWav->onSeek, pWav->pUserData, &header, pWav->container, &fmt);
3244
3245 /*
3246 dr_wav may need to read the contents of the chunk, so we now need to seek back to the position before
3247 we called the callback.
3248 */
3249 if (callbackBytesRead > 0) {
3250 if (drwav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData) == DRWAV_FALSE) {
3251 return DRWAV_FALSE;
3252 }
3253 }
3254 }
3255
3256
3257 /* Explicitly handle known chunks first. */
3258
3259 /* "fmt " */
3260 if (((pWav->container == drwav_container_riff || pWav->container == drwav_container_rifx || pWav->container == drwav_container_rf64) && drwav_fourcc_equal(header.id.fourcc, "fmt ")) ||
3261 ((pWav->container == drwav_container_w64) && drwav_guid_equal(header.id.guid, drwavGUID_W64_FMT))) {
3262 drwav_uint8 fmtData[16];
3263
3264 foundChunk_fmt = DRWAV_TRUE;
3265
3266 if (pWav->onRead(pWav->pUserData, fmtData, sizeof(fmtData)) != sizeof(fmtData)) {
3267 return DRWAV_FALSE;
3268 }
3269 cursor += sizeof(fmtData);
3270
3271 fmt.formatTag = drwav_bytes_to_u16_ex(fmtData + 0, pWav->container);
3272 fmt.channels = drwav_bytes_to_u16_ex(fmtData + 2, pWav->container);
3273 fmt.sampleRate = drwav_bytes_to_u32_ex(fmtData + 4, pWav->container);
3274 fmt.avgBytesPerSec = drwav_bytes_to_u32_ex(fmtData + 8, pWav->container);
3275 fmt.blockAlign = drwav_bytes_to_u16_ex(fmtData + 12, pWav->container);
3276 fmt.bitsPerSample = drwav_bytes_to_u16_ex(fmtData + 14, pWav->container);
3277
3278 fmt.extendedSize = 0;
3279 fmt.validBitsPerSample = 0;
3280 fmt.channelMask = 0;
3281 DRWAV_ZERO_MEMORY(fmt.subFormat, sizeof(fmt.subFormat));
3282
3283 if (header.sizeInBytes > 16) {
3284 drwav_uint8 fmt_cbSize[2];
3285 int bytesReadSoFar = 0;
3286
3287 if (pWav->onRead(pWav->pUserData, fmt_cbSize, sizeof(fmt_cbSize)) != sizeof(fmt_cbSize)) {
3288 return DRWAV_FALSE; /* Expecting more data. */
3289 }
3290 cursor += sizeof(fmt_cbSize);
3291
3292 bytesReadSoFar = 18;
3293
3294 fmt.extendedSize = drwav_bytes_to_u16_ex(fmt_cbSize, pWav->container);
3295 if (fmt.extendedSize > 0) {
3296 /* Simple validation. */
3297 if (fmt.formatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
3298 if (fmt.extendedSize != 22) {
3299 return DRWAV_FALSE;
3300 }
3301 }
3302
3303 if (fmt.formatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
3304 drwav_uint8 fmtext[22];
3305
3306 if (pWav->onRead(pWav->pUserData, fmtext, fmt.extendedSize) != fmt.extendedSize) {
3307 return DRWAV_FALSE; /* Expecting more data. */
3308 }
3309
3310 fmt.validBitsPerSample = drwav_bytes_to_u16_ex(fmtext + 0, pWav->container);
3311 fmt.channelMask = drwav_bytes_to_u32_ex(fmtext + 2, pWav->container);
3312 drwav_bytes_to_guid(fmtext + 6, fmt.subFormat);
3313 } else {
3314 if (pWav->onSeek(pWav->pUserData, fmt.extendedSize, drwav_seek_origin_current) == DRWAV_FALSE) {
3315 return DRWAV_FALSE;
3316 }
3317 }
3318 cursor += fmt.extendedSize;
3319
3320 bytesReadSoFar += fmt.extendedSize;
3321 }
3322
3323 /* Seek past any leftover bytes. For w64 the leftover will be defined based on the chunk size. */
3324 if (pWav->onSeek(pWav->pUserData, (int)(header.sizeInBytes - bytesReadSoFar), drwav_seek_origin_current) == DRWAV_FALSE) {
3325 return DRWAV_FALSE;
3326 }
3327 cursor += (header.sizeInBytes - bytesReadSoFar);
3328 }
3329
3330 if (header.paddingSize > 0) {
3331 if (drwav__seek_forward(pWav->onSeek, header.paddingSize, pWav->pUserData) == DRWAV_FALSE) {
3332 break;
3333 }
3334 cursor += header.paddingSize;
3335 }
3336
3337 /* Go to the next chunk. Don't include this chunk in metadata. */
3338 continue;
3339 }
3340
3341 /* "data" */
3342 if (((pWav->container == drwav_container_riff || pWav->container == drwav_container_rifx || pWav->container == drwav_container_rf64) && drwav_fourcc_equal(header.id.fourcc, "data")) ||
3343 ((pWav->container == drwav_container_w64) && drwav_guid_equal(header.id.guid, drwavGUID_W64_DATA))) {
3344 foundChunk_data = DRWAV_TRUE;
3345
3346 pWav->dataChunkDataPos = cursor;
3347
3348 if (pWav->container != drwav_container_rf64) { /* The data chunk size for RF64 will always be set to 0xFFFFFFFF here. It was set to it's true value earlier. */
3349 dataChunkSize = chunkSize;
3350 }
3351
3352 /* If we're running in sequential mode, or we're not reading metadata, we have enough now that we can get out of the loop. */
3353 if (sequential || !isProcessingMetadata) {
3354 break; /* No need to keep reading beyond the data chunk. */
3355 } else {
3356 chunkSize += header.paddingSize; /* <-- Make sure we seek past the padding. */
3357 if (drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData) == DRWAV_FALSE) {
3358 break;
3359 }
3360 cursor += chunkSize;
3361
3362 continue; /* There may be some more metadata to read. */
3363 }
3364 }
3365
3366 /* "fact". This is optional. Can use this to get the sample count which is useful for compressed formats. For RF64 we retrieved the sample count from the ds64 chunk earlier. */
3367 if (((pWav->container == drwav_container_riff || pWav->container == drwav_container_rifx || pWav->container == drwav_container_rf64) && drwav_fourcc_equal(header.id.fourcc, "fact")) ||
3368 ((pWav->container == drwav_container_w64) && drwav_guid_equal(header.id.guid, drwavGUID_W64_FACT))) {
3369 if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rifx) {
3370 drwav_uint8 sampleCount[4];
3371 if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCount, 4, &cursor) != 4) {
3372 return DRWAV_FALSE;
3373 }
3374
3375 chunkSize -= 4;
3376
3377 /*
3378 The sample count in the "fact" chunk is either unreliable, or I'm not understanding it properly. For now I am only enabling this
3379 for Microsoft ADPCM formats.
3380 */
3381 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
3382 sampleCountFromFactChunk = drwav_bytes_to_u32_ex(sampleCount, pWav->container);
3383 } else {
3384 sampleCountFromFactChunk = 0;
3385 }
3386 } else if (pWav->container == drwav_container_w64) {
3387 if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCountFromFactChunk, 8, &cursor) != 8) {
3388 return DRWAV_FALSE;
3389 }
3390
3391 chunkSize -= 8;
3392 } else if (pWav->container == drwav_container_rf64) {
3393 /* We retrieved the sample count from the ds64 chunk earlier so no need to do that here. */
3394 }
3395
3396 /* Seek to the next chunk in preparation for the next iteration. */
3397 chunkSize += header.paddingSize; /* <-- Make sure we seek past the padding. */
3398 if (drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData) == DRWAV_FALSE) {
3399 break;
3400 }
3401 cursor += chunkSize;
3402
3403 continue;
3404 }
3405
3406
3407 /* "COMM". AIFF/AIFC only. */
3408 if (pWav->container == drwav_container_aiff && drwav_fourcc_equal(header.id.fourcc, "COMM")) {
3409 drwav_uint8 commData[24];
3410 drwav_uint32 commDataBytesToRead;
3411 drwav_uint16 channels;
3412 drwav_uint32 frameCount;
3413 drwav_uint16 sampleSizeInBits;
3414 drwav_int64 sampleRate;
3415 drwav_uint16 compressionFormat;
3416
3417 foundChunk_fmt = DRWAV_TRUE;
3418
3419 if (isAIFCFormType) {
3420 commDataBytesToRead = 24;
3421 if (header.sizeInBytes < commDataBytesToRead) {
3422 return DRWAV_FALSE; /* Invalid COMM chunk. */
3423 }
3424 } else {
3425 commDataBytesToRead = 18;
3426 if (header.sizeInBytes != commDataBytesToRead) {
3427 return DRWAV_FALSE; /* INVALID COMM chunk. */
3428 }
3429 }
3430
3431 if (drwav__on_read(pWav->onRead, pWav->pUserData, commData, commDataBytesToRead, &cursor) != commDataBytesToRead) {
3432 return DRWAV_FALSE;
3433 }
3434
3435
3436 channels = drwav_bytes_to_u16_ex (commData + 0, pWav->container);
3437 frameCount = drwav_bytes_to_u32_ex (commData + 2, pWav->container);
3438 sampleSizeInBits = drwav_bytes_to_u16_ex (commData + 6, pWav->container);
3439 sampleRate = drwav_aiff_extented_to_s64(commData + 8);
3440
3441 if (sampleRate < 0 || sampleRate > 0xFFFFFFFF) {
3442 return DRWAV_FALSE; /* Invalid sample rate. */
3443 }
3444
3445 if (isAIFCFormType) {
3446 const drwav_uint8* type = commData + 18;
3447
3448 if (drwav_fourcc_equal(type, "NONE")) {
3449 compressionFormat = DR_WAVE_FORMAT_PCM; /* PCM, big-endian. */
3450 } else if (drwav_fourcc_equal(type, "raw ")) {
3451 compressionFormat = DR_WAVE_FORMAT_PCM;
3452
3453 /* In my testing, it looks like when the "raw " compression type is used, 8-bit samples should be considered unsigned. */
3454 if (sampleSizeInBits == 8) {
3455 pWav->aiff.isUnsigned = DRWAV_TRUE;
3456 }
3457 } else if (drwav_fourcc_equal(type, "sowt")) {
3458 compressionFormat = DR_WAVE_FORMAT_PCM; /* PCM, little-endian. */
3459 pWav->aiff.isLE = DRWAV_TRUE;
3460 } else if (drwav_fourcc_equal(type, "fl32") || drwav_fourcc_equal(type, "fl64") || drwav_fourcc_equal(type, "FL32") || drwav_fourcc_equal(type, "FL64")) {
3461 compressionFormat = DR_WAVE_FORMAT_IEEE_FLOAT;
3462 } else if (drwav_fourcc_equal(type, "alaw") || drwav_fourcc_equal(type, "ALAW")) {
3463 compressionFormat = DR_WAVE_FORMAT_ALAW;
3464 } else if (drwav_fourcc_equal(type, "ulaw") || drwav_fourcc_equal(type, "ULAW")) {
3465 compressionFormat = DR_WAVE_FORMAT_MULAW;
3466 } else if (drwav_fourcc_equal(type, "ima4")) {
3467 compressionFormat = DR_WAVE_FORMAT_DVI_ADPCM;
3468 sampleSizeInBits = 4;
3469
3470 /*
3471 I haven't been able to figure out how to get correct decoding for IMA ADPCM. Until this is figured out
3472 we'll need to abort when we encounter such an encoding. Advice welcome!
3473 */
3474 return DRWAV_FALSE;
3475 } else {
3476 return DRWAV_FALSE; /* Unknown or unsupported compression format. Need to abort. */
3477 }
3478 } else {
3479 compressionFormat = DR_WAVE_FORMAT_PCM; /* It's a standard AIFF form which is always compressed. */
3480 }
3481
3482 /* With AIFF we want to use the explicitly defined frame count rather than deriving it from the size of the chunk. */
3483 aiffFrameCount = frameCount;
3484
3485 /* We should now have enough information to fill out our fmt structure. */
3486 fmt.formatTag = compressionFormat;
3487 fmt.channels = channels;
3488 fmt.sampleRate = (drwav_uint32)sampleRate;
3489 fmt.bitsPerSample = sampleSizeInBits;
3490 fmt.blockAlign = (drwav_uint16)(fmt.channels * fmt.bitsPerSample / 8);
3491 fmt.avgBytesPerSec = fmt.blockAlign * fmt.sampleRate;
3492
3493 if (fmt.blockAlign == 0 && compressionFormat == DR_WAVE_FORMAT_DVI_ADPCM) {
3494 fmt.blockAlign = 34 * fmt.channels;
3495 }
3496
3497 /*
3498 Weird one. I've seen some alaw and ulaw encoded files that for some reason set the bits per sample to 16 when
3499 it should be 8. To get this working I need to explicitly check for this and change it.
3500 */
3501 if (compressionFormat == DR_WAVE_FORMAT_ALAW || compressionFormat == DR_WAVE_FORMAT_MULAW) {
3502 if (fmt.bitsPerSample > 8) {
3503 fmt.bitsPerSample = 8;
3504 fmt.blockAlign = fmt.channels;
3505 }
3506 }
3507
3508 /* In AIFF, samples are padded to 8 byte boundaries. We need to round up our bits per sample here. */
3509 fmt.bitsPerSample += (fmt.bitsPerSample & 7);
3510
3511
3512 /* If the form type is AIFC there will be some additional data in the chunk. We need to seek past it. */
3513 if (isAIFCFormType) {
3514 if (drwav__seek_forward(pWav->onSeek, (chunkSize - commDataBytesToRead), pWav->pUserData) == DRWAV_FALSE) {
3515 return DRWAV_FALSE;
3516 }
3517 cursor += (chunkSize - commDataBytesToRead);
3518 }
3519
3520 /* Don't fall through or else we'll end up treating this chunk as metadata which is incorrect. */
3521 continue;
3522 }
3523
3524
3525 /* "SSND". AIFF/AIFC only. This is the AIFF equivalent of the "data" chunk. */
3526 if (pWav->container == drwav_container_aiff && drwav_fourcc_equal(header.id.fourcc, "SSND")) {
3527 drwav_uint8 offsetAndBlockSizeData[8];
3528 drwav_uint32 offset;
3529
3530 foundChunk_data = DRWAV_TRUE;
3531
3532 if (drwav__on_read(pWav->onRead, pWav->pUserData, offsetAndBlockSizeData, sizeof(offsetAndBlockSizeData), &cursor) != sizeof(offsetAndBlockSizeData)) {
3533 return DRWAV_FALSE;
3534 }
3535
3536 /* We need to seek forward by the offset. */
3537 offset = drwav_bytes_to_u32_ex(offsetAndBlockSizeData + 0, pWav->container);
3538 if (drwav__seek_forward(pWav->onSeek, offset, pWav->pUserData) == DRWAV_FALSE) {
3539 return DRWAV_FALSE;
3540 }
3541 cursor += offset;
3542
3543 pWav->dataChunkDataPos = cursor;
3544 dataChunkSize = chunkSize;
3545
3546 /* If we're running in sequential mode, or we're not reading metadata, we have enough now that we can get out of the loop. */
3547 if (sequential || !isProcessingMetadata) {
3548 break; /* No need to keep reading beyond the data chunk. */
3549 } else {
3550 if (drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData) == DRWAV_FALSE) {
3551 break;
3552 }
3553 cursor += chunkSize;
3554
3555 continue; /* There may be some more metadata to read. */
3556 }
3557 }
3558
3559
3560
3561 /* Getting here means it's not a chunk that we care about internally, but might need to be handled as metadata by the caller. */
3562 if (isProcessingMetadata) {
3563 drwav__metadata_process_chunk(&metadataParser, &header, drwav_metadata_type_all_including_unknown);
3564
3565 /* Go back to the start of the chunk so we can normalize the position of the cursor. */
3566 if (drwav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData) == DRWAV_FALSE) {
3567 break; /* Failed to seek. Can't reliable read the remaining chunks. Get out. */
3568 }
3569 }
3570
3571
3572 /* Make sure we skip past the content of this chunk before we go to the next one. */
3573 chunkSize += header.paddingSize; /* <-- Make sure we seek past the padding. */
3574 if (drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData) == DRWAV_FALSE) {
3575 break;
3576 }
3577 cursor += chunkSize;
3578 }
3579
3580 /* There's some mandatory chunks that must exist. If they were not found in the iteration above we must abort. */
3581 if (!foundChunk_fmt || !foundChunk_data) {
3582 return DRWAV_FALSE;
3583 }
3584
3585 /* Basic validation. */
3586 if ((fmt.sampleRate == 0 || fmt.sampleRate > DRWAV_MAX_SAMPLE_RATE ) ||
3587 (fmt.channels == 0 || fmt.channels > DRWAV_MAX_CHANNELS ) ||
3588 (fmt.bitsPerSample == 0 || fmt.bitsPerSample > DRWAV_MAX_BITS_PER_SAMPLE) ||
3589 fmt.blockAlign == 0) {
3590 return DRWAV_FALSE; /* Probably an invalid WAV file. */
3591 }
3592
3593 /* Translate the internal format. */
3594 translatedFormatTag = fmt.formatTag;
3595 if (translatedFormatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
3596 translatedFormatTag = drwav_bytes_to_u16_ex(fmt.subFormat + 0, pWav->container);
3597 }
3598
3599 /* We may have moved passed the data chunk. If so we need to move back. If running in sequential mode we can assume we are already sitting on the data chunk. */
3600 if (!sequential) {
3601 if (!drwav__seek_from_start(pWav->onSeek, pWav->dataChunkDataPos, pWav->pUserData)) {
3602 return DRWAV_FALSE;
3603 }
3604 cursor = pWav->dataChunkDataPos;
3605 }
3606
3607
3608 /*
3609 At this point we should have done the initial parsing of each of our chunks, but we now need to
3610 do a second pass to extract the actual contents of the metadata (the first pass just calculated
3611 the length of the memory allocation).
3612
3613 We only do this if we've actually got metadata to parse.
3614 */
3615 if (isProcessingMetadata && metadataParser.metadataCount > 0) {
3616 if (drwav__seek_from_start(pWav->onSeek, metadataStartPos, pWav->pUserData) == DRWAV_FALSE) {
3617 return DRWAV_FALSE;
3618 }
3619
3620 result = drwav__metadata_alloc(&metadataParser, &pWav->allocationCallbacks);
3621 if (result != DRWAV_SUCCESS) {
3622 return DRWAV_FALSE;
3623 }
3624
3625 metadataParser.stage = drwav__metadata_parser_stage_read;
3626
3627 for (;;) {
3628 drwav_chunk_header header;
3629 drwav_uint64 metadataBytesRead;
3630
3631 result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header);
3632 if (result != DRWAV_SUCCESS) {
3633 break;
3634 }
3635
3636 metadataBytesRead = drwav__metadata_process_chunk(&metadataParser, &header, drwav_metadata_type_all_including_unknown);
3637
3638 /* Move to the end of the chunk so we can keep iterating. */
3639 if (drwav__seek_forward(pWav->onSeek, (header.sizeInBytes + header.paddingSize) - metadataBytesRead, pWav->pUserData) == DRWAV_FALSE) {
3640 drwav_free(metadataParser.pMetadata, &pWav->allocationCallbacks);
3641 return DRWAV_FALSE;
3642 }
3643 }
3644
3645 /* Getting here means we're finished parsing the metadata. */
3646 pWav->pMetadata = metadataParser.pMetadata;
3647 pWav->metadataCount = metadataParser.metadataCount;
3648 }
3649
3650
3651 /* At this point we should be sitting on the first byte of the raw audio data. */
3652
3653 /*
3654 I've seen a WAV file in the wild where a RIFF-ecapsulated file has the size of it's "RIFF" and
3655 "data" chunks set to 0xFFFFFFFF when the file is definitely not that big. In this case we're
3656 going to have to calculate the size by reading and discarding bytes, and then seeking back. We
3657 cannot do this in sequential mode. We just assume that the rest of the file is audio data.
3658 */
3659 if (dataChunkSize == 0xFFFFFFFF && (pWav->container == drwav_container_riff || pWav->container == drwav_container_rifx) && pWav->isSequentialWrite == DRWAV_FALSE) {
3660 dataChunkSize = 0;
3661
3662 for (;;) {
3663 drwav_uint8 temp[4096];
3664 size_t bytesRead = pWav->onRead(pWav->pUserData, temp, sizeof(temp));
3665 dataChunkSize += bytesRead;
3666
3667 if (bytesRead < sizeof(temp)) {
3668 break;
3669 }
3670 }
3671 }
3672
3673 if (drwav__seek_from_start(pWav->onSeek, pWav->dataChunkDataPos, pWav->pUserData) == DRWAV_FALSE) {
3674 drwav_free(pWav->pMetadata, &pWav->allocationCallbacks);
3675 return DRWAV_FALSE;
3676 }
3677
3678
3679 pWav->fmt = fmt;
3680 pWav->sampleRate = fmt.sampleRate;
3681 pWav->channels = fmt.channels;
3682 pWav->bitsPerSample = fmt.bitsPerSample;
3683 pWav->bytesRemaining = dataChunkSize;
3684 pWav->translatedFormatTag = translatedFormatTag;
3685 pWav->dataChunkDataSize = dataChunkSize;
3686
3687 if (sampleCountFromFactChunk != 0) {
3688 pWav->totalPCMFrameCount = sampleCountFromFactChunk;
3689 } else if (aiffFrameCount != 0) {
3690 pWav->totalPCMFrameCount = aiffFrameCount;
3691 } else {
3692 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
3693 if (bytesPerFrame == 0) {
3694 drwav_free(pWav->pMetadata, &pWav->allocationCallbacks);
3695 return DRWAV_FALSE; /* Invalid file. */
3696 }
3697
3698 pWav->totalPCMFrameCount = dataChunkSize / bytesPerFrame;
3699
3700 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
3701 drwav_uint64 totalBlockHeaderSizeInBytes;
3702 drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
3703
3704 /* Make sure any trailing partial block is accounted for. */
3705 if ((blockCount * fmt.blockAlign) < dataChunkSize) {
3706 blockCount += 1;
3707 }
3708
3709 /* We decode two samples per byte. There will be blockCount headers in the data chunk. This is enough to know how to calculate the total PCM frame count. */
3710 totalBlockHeaderSizeInBytes = blockCount * (6*fmt.channels);
3711 pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels;
3712 }
3713 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
3714 drwav_uint64 totalBlockHeaderSizeInBytes;
3715 drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
3716
3717 /* Make sure any trailing partial block is accounted for. */
3718 if ((blockCount * fmt.blockAlign) < dataChunkSize) {
3719 blockCount += 1;
3720 }
3721
3722 /* We decode two samples per byte. There will be blockCount headers in the data chunk. This is enough to know how to calculate the total PCM frame count. */
3723 totalBlockHeaderSizeInBytes = blockCount * (4*fmt.channels);
3724 pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels;
3725
3726 /* The header includes a decoded sample for each channel which acts as the initial predictor sample. */
3727 pWav->totalPCMFrameCount += blockCount;
3728 }
3729 }
3730
3731 /* Some formats only support a certain number of channels. */
3732 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
3733 if (pWav->channels > 2) {
3734 drwav_free(pWav->pMetadata, &pWav->allocationCallbacks);
3735 return DRWAV_FALSE;
3736 }
3737 }
3738
3739 /* The number of bytes per frame must be known. If not, it's an invalid file and not decodable. */
3740 if (drwav_get_bytes_per_pcm_frame(pWav) == 0) {
3741 drwav_free(pWav->pMetadata, &pWav->allocationCallbacks);
3742 return DRWAV_FALSE;
3743 }
3744
3745#ifdef DR_WAV_LIBSNDFILE_COMPAT
3746 /*
3747 I use libsndfile as a benchmark for testing, however in the version I'm using (from the Windows installer on the libsndfile website),
3748 it appears the total sample count libsndfile uses for MS-ADPCM is incorrect. It would seem they are computing the total sample count
3749 from the number of blocks, however this results in the inclusion of extra silent samples at the end of the last block. The correct
3750 way to know the total sample count is to inspect the "fact" chunk, which should always be present for compressed formats, and should
3751 always include the sample count. This little block of code below is only used to emulate the libsndfile logic so I can properly run my
3752 correctness tests against libsndfile, and is disabled by default.
3753 */
3754 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
3755 drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
3756 pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (6*pWav->channels))) * 2)) / fmt.channels; /* x2 because two samples per byte. */
3757 }
3758 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
3759 drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign;
3760 pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (4*pWav->channels))) * 2) + (blockCount * pWav->channels)) / fmt.channels;
3761 }
3762#endif
3763
3764 return DRWAV_TRUE;
3765}
3766
3767DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
3768{
3769 return drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0, pAllocationCallbacks);
3770}
3771
3772DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
3773{
3774 if (!drwav_preinit(pWav, onRead, onSeek, pReadSeekUserData, pAllocationCallbacks)) {
3775 return DRWAV_FALSE;
3776 }
3777
3778 return drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
3779}
3780
3781DRWAV_API drwav_bool32 drwav_init_with_metadata(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
3782{
3783 if (!drwav_preinit(pWav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
3784 return DRWAV_FALSE;
3785 }
3786
3787 return drwav_init__internal(pWav, NULL, NULL, flags | DRWAV_WITH_METADATA);
3788}
3789
3790DRWAV_API drwav_metadata* drwav_take_ownership_of_metadata(drwav* pWav)
3791{
3792 drwav_metadata *result = pWav->pMetadata;
3793
3794 pWav->pMetadata = NULL;
3795 pWav->metadataCount = 0;
3796
3797 return result;
3798}
3799
3800
3801DRWAV_PRIVATE size_t drwav__write(drwav* pWav, const void* pData, size_t dataSize)
3802{
3803 DRWAV_ASSERT(pWav != NULL);
3804 DRWAV_ASSERT(pWav->onWrite != NULL);
3805
3806 /* Generic write. Assumes no byte reordering required. */
3807 return pWav->onWrite(pWav->pUserData, pData, dataSize);
3808}
3809
3810DRWAV_PRIVATE size_t drwav__write_byte(drwav* pWav, drwav_uint8 byte)
3811{
3812 DRWAV_ASSERT(pWav != NULL);
3813 DRWAV_ASSERT(pWav->onWrite != NULL);
3814
3815 return pWav->onWrite(pWav->pUserData, &byte, 1);
3816}
3817
3818DRWAV_PRIVATE size_t drwav__write_u16ne_to_le(drwav* pWav, drwav_uint16 value)
3819{
3820 DRWAV_ASSERT(pWav != NULL);
3821 DRWAV_ASSERT(pWav->onWrite != NULL);
3822
3823 if (!drwav__is_little_endian()) {
3824 value = drwav__bswap16(value);
3825 }
3826
3827 return drwav__write(pWav, &value, 2);
3828}
3829
3830DRWAV_PRIVATE size_t drwav__write_u32ne_to_le(drwav* pWav, drwav_uint32 value)
3831{
3832 DRWAV_ASSERT(pWav != NULL);
3833 DRWAV_ASSERT(pWav->onWrite != NULL);
3834
3835 if (!drwav__is_little_endian()) {
3836 value = drwav__bswap32(value);
3837 }
3838
3839 return drwav__write(pWav, &value, 4);
3840}
3841
3842DRWAV_PRIVATE size_t drwav__write_u64ne_to_le(drwav* pWav, drwav_uint64 value)
3843{
3844 DRWAV_ASSERT(pWav != NULL);
3845 DRWAV_ASSERT(pWav->onWrite != NULL);
3846
3847 if (!drwav__is_little_endian()) {
3848 value = drwav__bswap64(value);
3849 }
3850
3851 return drwav__write(pWav, &value, 8);
3852}
3853
3854DRWAV_PRIVATE size_t drwav__write_f32ne_to_le(drwav* pWav, float value)
3855{
3856 union {
3857 drwav_uint32 u32;
3858 float f32;
3859 } u;
3860
3861 DRWAV_ASSERT(pWav != NULL);
3862 DRWAV_ASSERT(pWav->onWrite != NULL);
3863
3864 u.f32 = value;
3865
3866 if (!drwav__is_little_endian()) {
3867 u.u32 = drwav__bswap32(u.u32);
3868 }
3869
3870 return drwav__write(pWav, &u.u32, 4);
3871}
3872
3873DRWAV_PRIVATE size_t drwav__write_or_count(drwav* pWav, const void* pData, size_t dataSize)
3874{
3875 if (pWav == NULL) {
3876 return dataSize;
3877 }
3878
3879 return drwav__write(pWav, pData, dataSize);
3880}
3881
3882DRWAV_PRIVATE size_t drwav__write_or_count_byte(drwav* pWav, drwav_uint8 byte)
3883{
3884 if (pWav == NULL) {
3885 return 1;
3886 }
3887
3888 return drwav__write_byte(pWav, byte);
3889}
3890
3891DRWAV_PRIVATE size_t drwav__write_or_count_u16ne_to_le(drwav* pWav, drwav_uint16 value)
3892{
3893 if (pWav == NULL) {
3894 return 2;
3895 }
3896
3897 return drwav__write_u16ne_to_le(pWav, value);
3898}
3899
3900DRWAV_PRIVATE size_t drwav__write_or_count_u32ne_to_le(drwav* pWav, drwav_uint32 value)
3901{
3902 if (pWav == NULL) {
3903 return 4;
3904 }
3905
3906 return drwav__write_u32ne_to_le(pWav, value);
3907}
3908
3909#if 0 /* Unused for now. */
3910DRWAV_PRIVATE size_t drwav__write_or_count_u64ne_to_le(drwav* pWav, drwav_uint64 value)
3911{
3912 if (pWav == NULL) {
3913 return 8;
3914 }
3915
3916 return drwav__write_u64ne_to_le(pWav, value);
3917}
3918#endif
3919
3920DRWAV_PRIVATE size_t drwav__write_or_count_f32ne_to_le(drwav* pWav, float value)
3921{
3922 if (pWav == NULL) {
3923 return 4;
3924 }
3925
3926 return drwav__write_f32ne_to_le(pWav, value);
3927}
3928
3929DRWAV_PRIVATE size_t drwav__write_or_count_string_to_fixed_size_buf(drwav* pWav, char* str, size_t bufFixedSize)
3930{
3931 size_t len;
3932
3933 if (pWav == NULL) {
3934 return bufFixedSize;
3935 }
3936
3937 len = drwav__strlen_clamped(str, bufFixedSize);
3938 drwav__write_or_count(pWav, str, len);
3939
3940 if (len < bufFixedSize) {
3941 size_t i;
3942 for (i = 0; i < bufFixedSize - len; ++i) {
3943 drwav__write_byte(pWav, 0);
3944 }
3945 }
3946
3947 return bufFixedSize;
3948}
3949
3950
3951/* pWav can be NULL meaning just count the bytes that would be written. */
3952DRWAV_PRIVATE size_t drwav__write_or_count_metadata(drwav* pWav, drwav_metadata* pMetadatas, drwav_uint32 metadataCount)
3953{
3954 size_t bytesWritten = 0;
3955 drwav_bool32 hasListAdtl = DRWAV_FALSE;
3956 drwav_bool32 hasListInfo = DRWAV_FALSE;
3957 drwav_uint32 iMetadata;
3958
3959 if (pMetadatas == NULL || metadataCount == 0) {
3960 return 0;
3961 }
3962
3963 for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) {
3964 drwav_metadata* pMetadata = &pMetadatas[iMetadata];
3965 drwav_uint32 chunkSize = 0;
3966
3967 if ((pMetadata->type & drwav_metadata_type_list_all_info_strings) || (pMetadata->type == drwav_metadata_type_unknown && pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_info_list)) {
3968 hasListInfo = DRWAV_TRUE;
3969 }
3970
3971 if ((pMetadata->type & drwav_metadata_type_list_all_adtl) || (pMetadata->type == drwav_metadata_type_unknown && pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_adtl_list)) {
3972 hasListAdtl = DRWAV_TRUE;
3973 }
3974
3975 switch (pMetadata->type) {
3976 case drwav_metadata_type_smpl:
3977 {
3978 drwav_uint32 iLoop;
3979
3980 chunkSize = DRWAV_SMPL_BYTES + DRWAV_SMPL_LOOP_BYTES * pMetadata->data.smpl.sampleLoopCount + pMetadata->data.smpl.samplerSpecificDataSizeInBytes;
3981
3982 bytesWritten += drwav__write_or_count(pWav, "smpl", 4);
3983 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
3984
3985 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.manufacturerId);
3986 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.productId);
3987 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.samplePeriodNanoseconds);
3988 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.midiUnityNote);
3989 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.midiPitchFraction);
3990 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.smpteFormat);
3991 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.smpteOffset);
3992 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.sampleLoopCount);
3993 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.samplerSpecificDataSizeInBytes);
3994
3995 for (iLoop = 0; iLoop < pMetadata->data.smpl.sampleLoopCount; ++iLoop) {
3996 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].cuePointId);
3997 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].type);
3998 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].firstSampleByteOffset);
3999 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].lastSampleByteOffset);
4000 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].sampleFraction);
4001 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.smpl.pLoops[iLoop].playCount);
4002 }
4003
4004 if (pMetadata->data.smpl.samplerSpecificDataSizeInBytes > 0) {
4005 bytesWritten += drwav__write_or_count(pWav, pMetadata->data.smpl.pSamplerSpecificData, pMetadata->data.smpl.samplerSpecificDataSizeInBytes);
4006 }
4007 } break;
4008
4009 case drwav_metadata_type_inst:
4010 {
4011 chunkSize = DRWAV_INST_BYTES;
4012
4013 bytesWritten += drwav__write_or_count(pWav, "inst", 4);
4014 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
4015 bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.midiUnityNote, 1);
4016 bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.fineTuneCents, 1);
4017 bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.gainDecibels, 1);
4018 bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.lowNote, 1);
4019 bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.highNote, 1);
4020 bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.lowVelocity, 1);
4021 bytesWritten += drwav__write_or_count(pWav, &pMetadata->data.inst.highVelocity, 1);
4022 } break;
4023
4024 case drwav_metadata_type_cue:
4025 {
4026 drwav_uint32 iCuePoint;
4027
4028 chunkSize = DRWAV_CUE_BYTES + DRWAV_CUE_POINT_BYTES * pMetadata->data.cue.cuePointCount;
4029
4030 bytesWritten += drwav__write_or_count(pWav, "cue ", 4);
4031 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
4032 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.cuePointCount);
4033 for (iCuePoint = 0; iCuePoint < pMetadata->data.cue.cuePointCount; ++iCuePoint) {
4034 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].id);
4035 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].playOrderPosition);
4036 bytesWritten += drwav__write_or_count(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].dataChunkId, 4);
4037 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].chunkStart);
4038 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].blockStart);
4039 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.cue.pCuePoints[iCuePoint].sampleByteOffset);
4040 }
4041 } break;
4042
4043 case drwav_metadata_type_acid:
4044 {
4045 chunkSize = DRWAV_ACID_BYTES;
4046
4047 bytesWritten += drwav__write_or_count(pWav, "acid", 4);
4048 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
4049 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.acid.flags);
4050 bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.acid.midiUnityNote);
4051 bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.acid.reserved1);
4052 bytesWritten += drwav__write_or_count_f32ne_to_le(pWav, pMetadata->data.acid.reserved2);
4053 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.acid.numBeats);
4054 bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.acid.meterDenominator);
4055 bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.acid.meterNumerator);
4056 bytesWritten += drwav__write_or_count_f32ne_to_le(pWav, pMetadata->data.acid.tempo);
4057 } break;
4058
4059 case drwav_metadata_type_bext:
4060 {
4061 char reservedBuf[DRWAV_BEXT_RESERVED_BYTES];
4062 drwav_uint32 timeReferenceLow;
4063 drwav_uint32 timeReferenceHigh;
4064
4065 chunkSize = DRWAV_BEXT_BYTES + pMetadata->data.bext.codingHistorySize;
4066
4067 bytesWritten += drwav__write_or_count(pWav, "bext", 4);
4068 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
4069
4070 bytesWritten += drwav__write_or_count_string_to_fixed_size_buf(pWav, pMetadata->data.bext.pDescription, DRWAV_BEXT_DESCRIPTION_BYTES);
4071 bytesWritten += drwav__write_or_count_string_to_fixed_size_buf(pWav, pMetadata->data.bext.pOriginatorName, DRWAV_BEXT_ORIGINATOR_NAME_BYTES);
4072 bytesWritten += drwav__write_or_count_string_to_fixed_size_buf(pWav, pMetadata->data.bext.pOriginatorReference, DRWAV_BEXT_ORIGINATOR_REF_BYTES);
4073 bytesWritten += drwav__write_or_count(pWav, pMetadata->data.bext.pOriginationDate, sizeof(pMetadata->data.bext.pOriginationDate));
4074 bytesWritten += drwav__write_or_count(pWav, pMetadata->data.bext.pOriginationTime, sizeof(pMetadata->data.bext.pOriginationTime));
4075
4076 timeReferenceLow = (drwav_uint32)(pMetadata->data.bext.timeReference & 0xFFFFFFFF);
4077 timeReferenceHigh = (drwav_uint32)(pMetadata->data.bext.timeReference >> 32);
4078 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, timeReferenceLow);
4079 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, timeReferenceHigh);
4080
4081 bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.version);
4082 bytesWritten += drwav__write_or_count(pWav, pMetadata->data.bext.pUMID, DRWAV_BEXT_UMID_BYTES);
4083 bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.loudnessValue);
4084 bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.loudnessRange);
4085 bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.maxTruePeakLevel);
4086 bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.maxMomentaryLoudness);
4087 bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.maxShortTermLoudness);
4088
4089 DRWAV_ZERO_MEMORY(reservedBuf, sizeof(reservedBuf));
4090 bytesWritten += drwav__write_or_count(pWav, reservedBuf, sizeof(reservedBuf));
4091
4092 if (pMetadata->data.bext.codingHistorySize > 0) {
4093 bytesWritten += drwav__write_or_count(pWav, pMetadata->data.bext.pCodingHistory, pMetadata->data.bext.codingHistorySize);
4094 }
4095 } break;
4096
4097 case drwav_metadata_type_unknown:
4098 {
4099 if (pMetadata->data.unknown.chunkLocation == drwav_metadata_location_top_level) {
4100 chunkSize = pMetadata->data.unknown.dataSizeInBytes;
4101
4102 bytesWritten += drwav__write_or_count(pWav, pMetadata->data.unknown.id, 4);
4103 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
4104 bytesWritten += drwav__write_or_count(pWav, pMetadata->data.unknown.pData, pMetadata->data.unknown.dataSizeInBytes);
4105 }
4106 } break;
4107
4108 default: break;
4109 }
4110 if ((chunkSize % 2) != 0) {
4111 bytesWritten += drwav__write_or_count_byte(pWav, 0);
4112 }
4113 }
4114
4115 if (hasListInfo) {
4116 drwav_uint32 chunkSize = 4; /* Start with 4 bytes for "INFO". */
4117 for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) {
4118 drwav_metadata* pMetadata = &pMetadatas[iMetadata];
4119
4120 if ((pMetadata->type & drwav_metadata_type_list_all_info_strings)) {
4121 chunkSize += 8; /* For id and string size. */
4122 chunkSize += pMetadata->data.infoText.stringLength + 1; /* Include null terminator. */
4123 } else if (pMetadata->type == drwav_metadata_type_unknown && pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_info_list) {
4124 chunkSize += 8; /* For id string size. */
4125 chunkSize += pMetadata->data.unknown.dataSizeInBytes;
4126 }
4127
4128 if ((chunkSize % 2) != 0) {
4129 chunkSize += 1;
4130 }
4131 }
4132
4133 bytesWritten += drwav__write_or_count(pWav, "LIST", 4);
4134 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
4135 bytesWritten += drwav__write_or_count(pWav, "INFO", 4);
4136
4137 for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) {
4138 drwav_metadata* pMetadata = &pMetadatas[iMetadata];
4139 drwav_uint32 subchunkSize = 0;
4140
4141 if (pMetadata->type & drwav_metadata_type_list_all_info_strings) {
4142 const char* pID = NULL;
4143
4144 switch (pMetadata->type) {
4145 case drwav_metadata_type_list_info_software: pID = "ISFT"; break;
4146 case drwav_metadata_type_list_info_copyright: pID = "ICOP"; break;
4147 case drwav_metadata_type_list_info_title: pID = "INAM"; break;
4148 case drwav_metadata_type_list_info_artist: pID = "IART"; break;
4149 case drwav_metadata_type_list_info_comment: pID = "ICMT"; break;
4150 case drwav_metadata_type_list_info_date: pID = "ICRD"; break;
4151 case drwav_metadata_type_list_info_genre: pID = "IGNR"; break;
4152 case drwav_metadata_type_list_info_album: pID = "IPRD"; break;
4153 case drwav_metadata_type_list_info_tracknumber: pID = "ITRK"; break;
4154 default: break;
4155 }
4156
4157 DRWAV_ASSERT(pID != NULL);
4158
4159 if (pMetadata->data.infoText.stringLength) {
4160 subchunkSize = pMetadata->data.infoText.stringLength + 1;
4161 bytesWritten += drwav__write_or_count(pWav, pID, 4);
4162 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, subchunkSize);
4163 bytesWritten += drwav__write_or_count(pWav, pMetadata->data.infoText.pString, pMetadata->data.infoText.stringLength);
4164 bytesWritten += drwav__write_or_count_byte(pWav, '\0');
4165 }
4166 } else if (pMetadata->type == drwav_metadata_type_unknown && pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_info_list) {
4167 if (pMetadata->data.unknown.dataSizeInBytes) {
4168 subchunkSize = pMetadata->data.unknown.dataSizeInBytes;
4169
4170 bytesWritten += drwav__write_or_count(pWav, pMetadata->data.unknown.id, 4);
4171 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.unknown.dataSizeInBytes);
4172 bytesWritten += drwav__write_or_count(pWav, pMetadata->data.unknown.pData, subchunkSize);
4173 }
4174 }
4175
4176 if ((subchunkSize % 2) != 0) {
4177 bytesWritten += drwav__write_or_count_byte(pWav, 0);
4178 }
4179 }
4180 }
4181
4182 if (hasListAdtl) {
4183 drwav_uint32 chunkSize = 4; /* start with 4 bytes for "adtl" */
4184
4185 for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) {
4186 drwav_metadata* pMetadata = &pMetadatas[iMetadata];
4187
4188 switch (pMetadata->type)
4189 {
4190 case drwav_metadata_type_list_label:
4191 case drwav_metadata_type_list_note:
4192 {
4193 chunkSize += 8; /* for id and chunk size */
4194 chunkSize += DRWAV_LIST_LABEL_OR_NOTE_BYTES;
4195
4196 if (pMetadata->data.labelOrNote.stringLength > 0) {
4197 chunkSize += pMetadata->data.labelOrNote.stringLength + 1;
4198 }
4199 } break;
4200
4201 case drwav_metadata_type_list_labelled_cue_region:
4202 {
4203 chunkSize += 8; /* for id and chunk size */
4204 chunkSize += DRWAV_LIST_LABELLED_TEXT_BYTES;
4205
4206 if (pMetadata->data.labelledCueRegion.stringLength > 0) {
4207 chunkSize += pMetadata->data.labelledCueRegion.stringLength + 1;
4208 }
4209 } break;
4210
4211 case drwav_metadata_type_unknown:
4212 {
4213 if (pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_adtl_list) {
4214 chunkSize += 8; /* for id and chunk size */
4215 chunkSize += pMetadata->data.unknown.dataSizeInBytes;
4216 }
4217 } break;
4218
4219 default: break;
4220 }
4221
4222 if ((chunkSize % 2) != 0) {
4223 chunkSize += 1;
4224 }
4225 }
4226
4227 bytesWritten += drwav__write_or_count(pWav, "LIST", 4);
4228 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, chunkSize);
4229 bytesWritten += drwav__write_or_count(pWav, "adtl", 4);
4230
4231 for (iMetadata = 0; iMetadata < metadataCount; ++iMetadata) {
4232 drwav_metadata* pMetadata = &pMetadatas[iMetadata];
4233 drwav_uint32 subchunkSize = 0;
4234
4235 switch (pMetadata->type)
4236 {
4237 case drwav_metadata_type_list_label:
4238 case drwav_metadata_type_list_note:
4239 {
4240 if (pMetadata->data.labelOrNote.stringLength > 0) {
4241 const char *pID = NULL;
4242
4243 if (pMetadata->type == drwav_metadata_type_list_label) {
4244 pID = "labl";
4245 }
4246 else if (pMetadata->type == drwav_metadata_type_list_note) {
4247 pID = "note";
4248 }
4249
4250 DRWAV_ASSERT(pID != NULL);
4251 DRWAV_ASSERT(pMetadata->data.labelOrNote.pString != NULL);
4252
4253 subchunkSize = DRWAV_LIST_LABEL_OR_NOTE_BYTES;
4254
4255 bytesWritten += drwav__write_or_count(pWav, pID, 4);
4256 subchunkSize += pMetadata->data.labelOrNote.stringLength + 1;
4257 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, subchunkSize);
4258
4259 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.labelOrNote.cuePointId);
4260 bytesWritten += drwav__write_or_count(pWav, pMetadata->data.labelOrNote.pString, pMetadata->data.labelOrNote.stringLength);
4261 bytesWritten += drwav__write_or_count_byte(pWav, '\0');
4262 }
4263 } break;
4264
4265 case drwav_metadata_type_list_labelled_cue_region:
4266 {
4267 subchunkSize = DRWAV_LIST_LABELLED_TEXT_BYTES;
4268
4269 bytesWritten += drwav__write_or_count(pWav, "ltxt", 4);
4270 if (pMetadata->data.labelledCueRegion.stringLength > 0) {
4271 subchunkSize += pMetadata->data.labelledCueRegion.stringLength + 1;
4272 }
4273 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, subchunkSize);
4274 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.labelledCueRegion.cuePointId);
4275 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, pMetadata->data.labelledCueRegion.sampleLength);
4276 bytesWritten += drwav__write_or_count(pWav, pMetadata->data.labelledCueRegion.purposeId, 4);
4277 bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.labelledCueRegion.country);
4278 bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.labelledCueRegion.language);
4279 bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.labelledCueRegion.dialect);
4280 bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.labelledCueRegion.codePage);
4281
4282 if (pMetadata->data.labelledCueRegion.stringLength > 0) {
4283 DRWAV_ASSERT(pMetadata->data.labelledCueRegion.pString != NULL);
4284
4285 bytesWritten += drwav__write_or_count(pWav, pMetadata->data.labelledCueRegion.pString, pMetadata->data.labelledCueRegion.stringLength);
4286 bytesWritten += drwav__write_or_count_byte(pWav, '\0');
4287 }
4288 } break;
4289
4290 case drwav_metadata_type_unknown:
4291 {
4292 if (pMetadata->data.unknown.chunkLocation == drwav_metadata_location_inside_adtl_list) {
4293 subchunkSize = pMetadata->data.unknown.dataSizeInBytes;
4294
4295 DRWAV_ASSERT(pMetadata->data.unknown.pData != NULL);
4296 bytesWritten += drwav__write_or_count(pWav, pMetadata->data.unknown.id, 4);
4297 bytesWritten += drwav__write_or_count_u32ne_to_le(pWav, subchunkSize);
4298 bytesWritten += drwav__write_or_count(pWav, pMetadata->data.unknown.pData, subchunkSize);
4299 }
4300 } break;
4301
4302 default: break;
4303 }
4304
4305 if ((subchunkSize % 2) != 0) {
4306 bytesWritten += drwav__write_or_count_byte(pWav, 0);
4307 }
4308 }
4309 }
4310
4311 DRWAV_ASSERT((bytesWritten % 2) == 0);
4312
4313 return bytesWritten;
4314}
4315
4316DRWAV_PRIVATE drwav_uint32 drwav__riff_chunk_size_riff(drwav_uint64 dataChunkSize, drwav_metadata* pMetadata, drwav_uint32 metadataCount)
4317{
4318 drwav_uint64 chunkSize = 4 + 24 + (drwav_uint64)drwav__write_or_count_metadata(NULL, pMetadata, metadataCount) + 8 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize); /* 4 = "WAVE". 24 = "fmt " chunk. 8 = "data" + u32 data size. */
4319 if (chunkSize > 0xFFFFFFFFUL) {
4320 chunkSize = 0xFFFFFFFFUL;
4321 }
4322
4323 return (drwav_uint32)chunkSize; /* Safe cast due to the clamp above. */
4324}
4325
4326DRWAV_PRIVATE drwav_uint32 drwav__data_chunk_size_riff(drwav_uint64 dataChunkSize)
4327{
4328 if (dataChunkSize <= 0xFFFFFFFFUL) {
4329 return (drwav_uint32)dataChunkSize;
4330 } else {
4331 return 0xFFFFFFFFUL;
4332 }
4333}
4334
4335DRWAV_PRIVATE drwav_uint64 drwav__riff_chunk_size_w64(drwav_uint64 dataChunkSize)
4336{
4337 drwav_uint64 dataSubchunkPaddingSize = drwav__chunk_padding_size_w64(dataChunkSize);
4338
4339 return 80 + 24 + dataChunkSize + dataSubchunkPaddingSize; /* +24 because W64 includes the size of the GUID and size fields. */
4340}
4341
4342DRWAV_PRIVATE drwav_uint64 drwav__data_chunk_size_w64(drwav_uint64 dataChunkSize)
4343{
4344 return 24 + dataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */
4345}
4346
4347DRWAV_PRIVATE drwav_uint64 drwav__riff_chunk_size_rf64(drwav_uint64 dataChunkSize, drwav_metadata *metadata, drwav_uint32 numMetadata)
4348{
4349 drwav_uint64 chunkSize = 4 + 36 + 24 + (drwav_uint64)drwav__write_or_count_metadata(NULL, metadata, numMetadata) + 8 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize); /* 4 = "WAVE". 36 = "ds64" chunk. 24 = "fmt " chunk. 8 = "data" + u32 data size. */
4350 if (chunkSize > 0xFFFFFFFFUL) {
4351 chunkSize = 0xFFFFFFFFUL;
4352 }
4353
4354 return chunkSize;
4355}
4356
4357DRWAV_PRIVATE drwav_uint64 drwav__data_chunk_size_rf64(drwav_uint64 dataChunkSize)
4358{
4359 return dataChunkSize;
4360}
4361
4362
4363
4364DRWAV_PRIVATE drwav_bool32 drwav_preinit_write(drwav* pWav, const drwav_data_format* pFormat, drwav_bool32 isSequential, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
4365{
4366 if (pWav == NULL || onWrite == NULL) {
4367 return DRWAV_FALSE;
4368 }
4369
4370 if (!isSequential && onSeek == NULL) {
4371 return DRWAV_FALSE; /* <-- onSeek is required when in non-sequential mode. */
4372 }
4373
4374 /* Not currently supporting compressed formats. Will need to add support for the "fact" chunk before we enable this. */
4375 if (pFormat->format == DR_WAVE_FORMAT_EXTENSIBLE) {
4376 return DRWAV_FALSE;
4377 }
4378 if (pFormat->format == DR_WAVE_FORMAT_ADPCM || pFormat->format == DR_WAVE_FORMAT_DVI_ADPCM) {
4379 return DRWAV_FALSE;
4380 }
4381
4382 DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav));
4383 pWav->onWrite = onWrite;
4384 pWav->onSeek = onSeek;
4385 pWav->pUserData = pUserData;
4386 pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks);
4387
4388 if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) {
4389 return DRWAV_FALSE; /* Invalid allocation callbacks. */
4390 }
4391
4392 pWav->fmt.formatTag = (drwav_uint16)pFormat->format;
4393 pWav->fmt.channels = (drwav_uint16)pFormat->channels;
4394 pWav->fmt.sampleRate = pFormat->sampleRate;
4395 pWav->fmt.avgBytesPerSec = (drwav_uint32)((pFormat->bitsPerSample * pFormat->sampleRate * pFormat->channels) / 8);
4396 pWav->fmt.blockAlign = (drwav_uint16)((pFormat->channels * pFormat->bitsPerSample) / 8);
4397 pWav->fmt.bitsPerSample = (drwav_uint16)pFormat->bitsPerSample;
4398 pWav->fmt.extendedSize = 0;
4399 pWav->isSequentialWrite = isSequential;
4400
4401 return DRWAV_TRUE;
4402}
4403
4404
4405DRWAV_PRIVATE drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount)
4406{
4407 /* The function assumes drwav_preinit_write() was called beforehand. */
4408
4409 size_t runningPos = 0;
4410 drwav_uint64 initialDataChunkSize = 0;
4411 drwav_uint64 chunkSizeFMT;
4412
4413 /*
4414 The initial values for the "RIFF" and "data" chunks depends on whether or not we are initializing in sequential mode or not. In
4415 sequential mode we set this to its final values straight away since they can be calculated from the total sample count. In non-
4416 sequential mode we initialize it all to zero and fill it out in drwav_uninit() using a backwards seek.
4417 */
4418 if (pWav->isSequentialWrite) {
4419 initialDataChunkSize = (totalSampleCount * pWav->fmt.bitsPerSample) / 8;
4420
4421 /*
4422 The RIFF container has a limit on the number of samples. drwav is not allowing this. There's no practical limits for Wave64
4423 so for the sake of simplicity I'm not doing any validation for that.
4424 */
4425 if (pFormat->container == drwav_container_riff) {
4426 if (initialDataChunkSize > (0xFFFFFFFFUL - 36)) {
4427 return DRWAV_FALSE; /* Not enough room to store every sample. */
4428 }
4429 }
4430 }
4431
4432 pWav->dataChunkDataSizeTargetWrite = initialDataChunkSize;
4433
4434
4435 /* "RIFF" chunk. */
4436 if (pFormat->container == drwav_container_riff) {
4437 drwav_uint32 chunkSizeRIFF = 28 + (drwav_uint32)initialDataChunkSize; /* +28 = "WAVE" + [sizeof "fmt " chunk] */
4438 runningPos += drwav__write(pWav, "RIFF", 4);
4439 runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeRIFF);
4440 runningPos += drwav__write(pWav, "WAVE", 4);
4441 } else if (pFormat->container == drwav_container_w64) {
4442 drwav_uint64 chunkSizeRIFF = 80 + 24 + initialDataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */
4443 runningPos += drwav__write(pWav, drwavGUID_W64_RIFF, 16);
4444 runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeRIFF);
4445 runningPos += drwav__write(pWav, drwavGUID_W64_WAVE, 16);
4446 } else if (pFormat->container == drwav_container_rf64) {
4447 runningPos += drwav__write(pWav, "RF64", 4);
4448 runningPos += drwav__write_u32ne_to_le(pWav, 0xFFFFFFFF); /* Always 0xFFFFFFFF for RF64. Set to a proper value in the "ds64" chunk. */
4449 runningPos += drwav__write(pWav, "WAVE", 4);
4450 } else {
4451 return DRWAV_FALSE; /* Container not supported for writing. */
4452 }
4453
4454
4455 /* "ds64" chunk (RF64 only). */
4456 if (pFormat->container == drwav_container_rf64) {
4457 drwav_uint32 initialds64ChunkSize = 28; /* 28 = [Size of RIFF (8 bytes)] + [Size of DATA (8 bytes)] + [Sample Count (8 bytes)] + [Table Length (4 bytes)]. Table length always set to 0. */
4458 drwav_uint64 initialRiffChunkSize = 8 + initialds64ChunkSize + initialDataChunkSize; /* +8 for the ds64 header. */
4459
4460 runningPos += drwav__write(pWav, "ds64", 4);
4461 runningPos += drwav__write_u32ne_to_le(pWav, initialds64ChunkSize); /* Size of ds64. */
4462 runningPos += drwav__write_u64ne_to_le(pWav, initialRiffChunkSize); /* Size of RIFF. Set to true value at the end. */
4463 runningPos += drwav__write_u64ne_to_le(pWav, initialDataChunkSize); /* Size of DATA. Set to true value at the end. */
4464 runningPos += drwav__write_u64ne_to_le(pWav, totalSampleCount); /* Sample count. */
4465 runningPos += drwav__write_u32ne_to_le(pWav, 0); /* Table length. Always set to zero in our case since we're not doing any other chunks than "DATA". */
4466 }
4467
4468
4469 /* "fmt " chunk. */
4470 if (pFormat->container == drwav_container_riff || pFormat->container == drwav_container_rf64) {
4471 chunkSizeFMT = 16;
4472 runningPos += drwav__write(pWav, "fmt ", 4);
4473 runningPos += drwav__write_u32ne_to_le(pWav, (drwav_uint32)chunkSizeFMT);
4474 } else if (pFormat->container == drwav_container_w64) {
4475 chunkSizeFMT = 40;
4476 runningPos += drwav__write(pWav, drwavGUID_W64_FMT, 16);
4477 runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeFMT);
4478 }
4479
4480 runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.formatTag);
4481 runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.channels);
4482 runningPos += drwav__write_u32ne_to_le(pWav, pWav->fmt.sampleRate);
4483 runningPos += drwav__write_u32ne_to_le(pWav, pWav->fmt.avgBytesPerSec);
4484 runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.blockAlign);
4485 runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.bitsPerSample);
4486
4487 /* TODO: is a 'fact' chunk required for DR_WAVE_FORMAT_IEEE_FLOAT? */
4488
4489 if (!pWav->isSequentialWrite && pWav->pMetadata != NULL && pWav->metadataCount > 0 && (pFormat->container == drwav_container_riff || pFormat->container == drwav_container_rf64)) {
4490 runningPos += drwav__write_or_count_metadata(pWav, pWav->pMetadata, pWav->metadataCount);
4491 }
4492
4493 pWav->dataChunkDataPos = runningPos;
4494
4495 /* "data" chunk. */
4496 if (pFormat->container == drwav_container_riff) {
4497 drwav_uint32 chunkSizeDATA = (drwav_uint32)initialDataChunkSize;
4498 runningPos += drwav__write(pWav, "data", 4);
4499 runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeDATA);
4500 } else if (pFormat->container == drwav_container_w64) {
4501 drwav_uint64 chunkSizeDATA = 24 + initialDataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */
4502 runningPos += drwav__write(pWav, drwavGUID_W64_DATA, 16);
4503 runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeDATA);
4504 } else if (pFormat->container == drwav_container_rf64) {
4505 runningPos += drwav__write(pWav, "data", 4);
4506 runningPos += drwav__write_u32ne_to_le(pWav, 0xFFFFFFFF); /* Always set to 0xFFFFFFFF for RF64. The true size of the data chunk is specified in the ds64 chunk. */
4507 }
4508
4509 /* Set some properties for the client's convenience. */
4510 pWav->container = pFormat->container;
4511 pWav->channels = (drwav_uint16)pFormat->channels;
4512 pWav->sampleRate = pFormat->sampleRate;
4513 pWav->bitsPerSample = (drwav_uint16)pFormat->bitsPerSample;
4514 pWav->translatedFormatTag = (drwav_uint16)pFormat->format;
4515 pWav->dataChunkDataPos = runningPos;
4516
4517 return DRWAV_TRUE;
4518}
4519
4520
4521DRWAV_API drwav_bool32 drwav_init_write(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
4522{
4523 if (!drwav_preinit_write(pWav, pFormat, DRWAV_FALSE, onWrite, onSeek, pUserData, pAllocationCallbacks)) {
4524 return DRWAV_FALSE;
4525 }
4526
4527 return drwav_init_write__internal(pWav, pFormat, 0); /* DRWAV_FALSE = Not Sequential */
4528}
4529
4530DRWAV_API drwav_bool32 drwav_init_write_sequential(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
4531{
4532 if (!drwav_preinit_write(pWav, pFormat, DRWAV_TRUE, onWrite, NULL, pUserData, pAllocationCallbacks)) {
4533 return DRWAV_FALSE;
4534 }
4535
4536 return drwav_init_write__internal(pWav, pFormat, totalSampleCount); /* DRWAV_TRUE = Sequential */
4537}
4538
4539DRWAV_API drwav_bool32 drwav_init_write_sequential_pcm_frames(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks)
4540{
4541 if (pFormat == NULL) {
4542 return DRWAV_FALSE;
4543 }
4544
4545 return drwav_init_write_sequential(pWav, pFormat, totalPCMFrameCount*pFormat->channels, onWrite, pUserData, pAllocationCallbacks);
4546}
4547
4548DRWAV_API drwav_bool32 drwav_init_write_with_metadata(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks, drwav_metadata* pMetadata, drwav_uint32 metadataCount)
4549{
4550 if (!drwav_preinit_write(pWav, pFormat, DRWAV_FALSE, onWrite, onSeek, pUserData, pAllocationCallbacks)) {
4551 return DRWAV_FALSE;
4552 }
4553
4554 pWav->pMetadata = pMetadata;
4555 pWav->metadataCount = metadataCount;
4556
4557 return drwav_init_write__internal(pWav, pFormat, 0);
4558}
4559
4560
4561DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalFrameCount, drwav_metadata* pMetadata, drwav_uint32 metadataCount)
4562{
4563 /* Casting totalFrameCount to drwav_int64 for VC6 compatibility. No issues in practice because nobody is going to exhaust the whole 63 bits. */
4564 drwav_uint64 targetDataSizeBytes = (drwav_uint64)((drwav_int64)totalFrameCount * pFormat->channels * pFormat->bitsPerSample/8.0);
4565 drwav_uint64 riffChunkSizeBytes;
4566 drwav_uint64 fileSizeBytes = 0;
4567
4568 if (pFormat->container == drwav_container_riff) {
4569 riffChunkSizeBytes = drwav__riff_chunk_size_riff(targetDataSizeBytes, pMetadata, metadataCount);
4570 fileSizeBytes = (8 + riffChunkSizeBytes); /* +8 because WAV doesn't include the size of the ChunkID and ChunkSize fields. */
4571 } else if (pFormat->container == drwav_container_w64) {
4572 riffChunkSizeBytes = drwav__riff_chunk_size_w64(targetDataSizeBytes);
4573 fileSizeBytes = riffChunkSizeBytes;
4574 } else if (pFormat->container == drwav_container_rf64) {
4575 riffChunkSizeBytes = drwav__riff_chunk_size_rf64(targetDataSizeBytes, pMetadata, metadataCount);
4576 fileSizeBytes = (8 + riffChunkSizeBytes); /* +8 because WAV doesn't include the size of the ChunkID and ChunkSize fields. */
4577 }
4578
4579 return fileSizeBytes;
4580}
4581
4582
4583#ifndef DR_WAV_NO_STDIO
4584
4585/* Errno */
4586/* drwav_result_from_errno() is only used for fopen() and wfopen() so putting it inside DR_WAV_NO_STDIO for now. If something else needs this later we can move it out. */
4587#include <errno.h>
4588DRWAV_PRIVATE drwav_result drwav_result_from_errno(int e)
4589{
4590 switch (e)
4591 {
4592 case 0: return DRWAV_SUCCESS;
4593 #ifdef EPERM
4594 case EPERM: return DRWAV_INVALID_OPERATION;
4595 #endif
4596 #ifdef ENOENT
4597 case ENOENT: return DRWAV_DOES_NOT_EXIST;
4598 #endif
4599 #ifdef ESRCH
4600 case ESRCH: return DRWAV_DOES_NOT_EXIST;
4601 #endif
4602 #ifdef EINTR
4603 case EINTR: return DRWAV_INTERRUPT;
4604 #endif
4605 #ifdef EIO
4606 case EIO: return DRWAV_IO_ERROR;
4607 #endif
4608 #ifdef ENXIO
4609 case ENXIO: return DRWAV_DOES_NOT_EXIST;
4610 #endif
4611 #ifdef E2BIG
4612 case E2BIG: return DRWAV_INVALID_ARGS;
4613 #endif
4614 #ifdef ENOEXEC
4615 case ENOEXEC: return DRWAV_INVALID_FILE;
4616 #endif
4617 #ifdef EBADF
4618 case EBADF: return DRWAV_INVALID_FILE;
4619 #endif
4620 #ifdef ECHILD
4621 case ECHILD: return DRWAV_ERROR;
4622 #endif
4623 #ifdef EAGAIN
4624 case EAGAIN: return DRWAV_UNAVAILABLE;
4625 #endif
4626 #ifdef ENOMEM
4627 case ENOMEM: return DRWAV_OUT_OF_MEMORY;
4628 #endif
4629 #ifdef EACCES
4630 case EACCES: return DRWAV_ACCESS_DENIED;
4631 #endif
4632 #ifdef EFAULT
4633 case EFAULT: return DRWAV_BAD_ADDRESS;
4634 #endif
4635 #ifdef ENOTBLK
4636 case ENOTBLK: return DRWAV_ERROR;
4637 #endif
4638 #ifdef EBUSY
4639 case EBUSY: return DRWAV_BUSY;
4640 #endif
4641 #ifdef EEXIST
4642 case EEXIST: return DRWAV_ALREADY_EXISTS;
4643 #endif
4644 #ifdef EXDEV
4645 case EXDEV: return DRWAV_ERROR;
4646 #endif
4647 #ifdef ENODEV
4648 case ENODEV: return DRWAV_DOES_NOT_EXIST;
4649 #endif
4650 #ifdef ENOTDIR
4651 case ENOTDIR: return DRWAV_NOT_DIRECTORY;
4652 #endif
4653 #ifdef EISDIR
4654 case EISDIR: return DRWAV_IS_DIRECTORY;
4655 #endif
4656 #ifdef EINVAL
4657 case EINVAL: return DRWAV_INVALID_ARGS;
4658 #endif
4659 #ifdef ENFILE
4660 case ENFILE: return DRWAV_TOO_MANY_OPEN_FILES;
4661 #endif
4662 #ifdef EMFILE
4663 case EMFILE: return DRWAV_TOO_MANY_OPEN_FILES;
4664 #endif
4665 #ifdef ENOTTY
4666 case ENOTTY: return DRWAV_INVALID_OPERATION;
4667 #endif
4668 #ifdef ETXTBSY
4669 case ETXTBSY: return DRWAV_BUSY;
4670 #endif
4671 #ifdef EFBIG
4672 case EFBIG: return DRWAV_TOO_BIG;
4673 #endif
4674 #ifdef ENOSPC
4675 case ENOSPC: return DRWAV_NO_SPACE;
4676 #endif
4677 #ifdef ESPIPE
4678 case ESPIPE: return DRWAV_BAD_SEEK;
4679 #endif
4680 #ifdef EROFS
4681 case EROFS: return DRWAV_ACCESS_DENIED;
4682 #endif
4683 #ifdef EMLINK
4684 case EMLINK: return DRWAV_TOO_MANY_LINKS;
4685 #endif
4686 #ifdef EPIPE
4687 case EPIPE: return DRWAV_BAD_PIPE;
4688 #endif
4689 #ifdef EDOM
4690 case EDOM: return DRWAV_OUT_OF_RANGE;
4691 #endif
4692 #ifdef ERANGE
4693 case ERANGE: return DRWAV_OUT_OF_RANGE;
4694 #endif
4695 #ifdef EDEADLK
4696 case EDEADLK: return DRWAV_DEADLOCK;
4697 #endif
4698 #ifdef ENAMETOOLONG
4699 case ENAMETOOLONG: return DRWAV_PATH_TOO_LONG;
4700 #endif
4701 #ifdef ENOLCK
4702 case ENOLCK: return DRWAV_ERROR;
4703 #endif
4704 #ifdef ENOSYS
4705 case ENOSYS: return DRWAV_NOT_IMPLEMENTED;
4706 #endif
4707 #ifdef ENOTEMPTY
4708 case ENOTEMPTY: return DRWAV_DIRECTORY_NOT_EMPTY;
4709 #endif
4710 #ifdef ELOOP
4711 case ELOOP: return DRWAV_TOO_MANY_LINKS;
4712 #endif
4713 #ifdef ENOMSG
4714 case ENOMSG: return DRWAV_NO_MESSAGE;
4715 #endif
4716 #ifdef EIDRM
4717 case EIDRM: return DRWAV_ERROR;
4718 #endif
4719 #ifdef ECHRNG
4720 case ECHRNG: return DRWAV_ERROR;
4721 #endif
4722 #ifdef EL2NSYNC
4723 case EL2NSYNC: return DRWAV_ERROR;
4724 #endif
4725 #ifdef EL3HLT
4726 case EL3HLT: return DRWAV_ERROR;
4727 #endif
4728 #ifdef EL3RST
4729 case EL3RST: return DRWAV_ERROR;
4730 #endif
4731 #ifdef ELNRNG
4732 case ELNRNG: return DRWAV_OUT_OF_RANGE;
4733 #endif
4734 #ifdef EUNATCH
4735 case EUNATCH: return DRWAV_ERROR;
4736 #endif
4737 #ifdef ENOCSI
4738 case ENOCSI: return DRWAV_ERROR;
4739 #endif
4740 #ifdef EL2HLT
4741 case EL2HLT: return DRWAV_ERROR;
4742 #endif
4743 #ifdef EBADE
4744 case EBADE: return DRWAV_ERROR;
4745 #endif
4746 #ifdef EBADR
4747 case EBADR: return DRWAV_ERROR;
4748 #endif
4749 #ifdef EXFULL
4750 case EXFULL: return DRWAV_ERROR;
4751 #endif
4752 #ifdef ENOANO
4753 case ENOANO: return DRWAV_ERROR;
4754 #endif
4755 #ifdef EBADRQC
4756 case EBADRQC: return DRWAV_ERROR;
4757 #endif
4758 #ifdef EBADSLT
4759 case EBADSLT: return DRWAV_ERROR;
4760 #endif
4761 #ifdef EBFONT
4762 case EBFONT: return DRWAV_INVALID_FILE;
4763 #endif
4764 #ifdef ENOSTR
4765 case ENOSTR: return DRWAV_ERROR;
4766 #endif
4767 #ifdef ENODATA
4768 case ENODATA: return DRWAV_NO_DATA_AVAILABLE;
4769 #endif
4770 #ifdef ETIME
4771 case ETIME: return DRWAV_TIMEOUT;
4772 #endif
4773 #ifdef ENOSR
4774 case ENOSR: return DRWAV_NO_DATA_AVAILABLE;
4775 #endif
4776 #ifdef ENONET
4777 case ENONET: return DRWAV_NO_NETWORK;
4778 #endif
4779 #ifdef ENOPKG
4780 case ENOPKG: return DRWAV_ERROR;
4781 #endif
4782 #ifdef EREMOTE
4783 case EREMOTE: return DRWAV_ERROR;
4784 #endif
4785 #ifdef ENOLINK
4786 case ENOLINK: return DRWAV_ERROR;
4787 #endif
4788 #ifdef EADV
4789 case EADV: return DRWAV_ERROR;
4790 #endif
4791 #ifdef ESRMNT
4792 case ESRMNT: return DRWAV_ERROR;
4793 #endif
4794 #ifdef ECOMM
4795 case ECOMM: return DRWAV_ERROR;
4796 #endif
4797 #ifdef EPROTO
4798 case EPROTO: return DRWAV_ERROR;
4799 #endif
4800 #ifdef EMULTIHOP
4801 case EMULTIHOP: return DRWAV_ERROR;
4802 #endif
4803 #ifdef EDOTDOT
4804 case EDOTDOT: return DRWAV_ERROR;
4805 #endif
4806 #ifdef EBADMSG
4807 case EBADMSG: return DRWAV_BAD_MESSAGE;
4808 #endif
4809 #ifdef EOVERFLOW
4810 case EOVERFLOW: return DRWAV_TOO_BIG;
4811 #endif
4812 #ifdef ENOTUNIQ
4813 case ENOTUNIQ: return DRWAV_NOT_UNIQUE;
4814 #endif
4815 #ifdef EBADFD
4816 case EBADFD: return DRWAV_ERROR;
4817 #endif
4818 #ifdef EREMCHG
4819 case EREMCHG: return DRWAV_ERROR;
4820 #endif
4821 #ifdef ELIBACC
4822 case ELIBACC: return DRWAV_ACCESS_DENIED;
4823 #endif
4824 #ifdef ELIBBAD
4825 case ELIBBAD: return DRWAV_INVALID_FILE;
4826 #endif
4827 #ifdef ELIBSCN
4828 case ELIBSCN: return DRWAV_INVALID_FILE;
4829 #endif
4830 #ifdef ELIBMAX
4831 case ELIBMAX: return DRWAV_ERROR;
4832 #endif
4833 #ifdef ELIBEXEC
4834 case ELIBEXEC: return DRWAV_ERROR;
4835 #endif
4836 #ifdef EILSEQ
4837 case EILSEQ: return DRWAV_INVALID_DATA;
4838 #endif
4839 #ifdef ERESTART
4840 case ERESTART: return DRWAV_ERROR;
4841 #endif
4842 #ifdef ESTRPIPE
4843 case ESTRPIPE: return DRWAV_ERROR;
4844 #endif
4845 #ifdef EUSERS
4846 case EUSERS: return DRWAV_ERROR;
4847 #endif
4848 #ifdef ENOTSOCK
4849 case ENOTSOCK: return DRWAV_NOT_SOCKET;
4850 #endif
4851 #ifdef EDESTADDRREQ
4852 case EDESTADDRREQ: return DRWAV_NO_ADDRESS;
4853 #endif
4854 #ifdef EMSGSIZE
4855 case EMSGSIZE: return DRWAV_TOO_BIG;
4856 #endif
4857 #ifdef EPROTOTYPE
4858 case EPROTOTYPE: return DRWAV_BAD_PROTOCOL;
4859 #endif
4860 #ifdef ENOPROTOOPT
4861 case ENOPROTOOPT: return DRWAV_PROTOCOL_UNAVAILABLE;
4862 #endif
4863 #ifdef EPROTONOSUPPORT
4864 case EPROTONOSUPPORT: return DRWAV_PROTOCOL_NOT_SUPPORTED;
4865 #endif
4866 #ifdef ESOCKTNOSUPPORT
4867 case ESOCKTNOSUPPORT: return DRWAV_SOCKET_NOT_SUPPORTED;
4868 #endif
4869 #ifdef EOPNOTSUPP
4870 case EOPNOTSUPP: return DRWAV_INVALID_OPERATION;
4871 #endif
4872 #ifdef EPFNOSUPPORT
4873 case EPFNOSUPPORT: return DRWAV_PROTOCOL_FAMILY_NOT_SUPPORTED;
4874 #endif
4875 #ifdef EAFNOSUPPORT
4876 case EAFNOSUPPORT: return DRWAV_ADDRESS_FAMILY_NOT_SUPPORTED;
4877 #endif
4878 #ifdef EADDRINUSE
4879 case EADDRINUSE: return DRWAV_ALREADY_IN_USE;
4880 #endif
4881 #ifdef EADDRNOTAVAIL
4882 case EADDRNOTAVAIL: return DRWAV_ERROR;
4883 #endif
4884 #ifdef ENETDOWN
4885 case ENETDOWN: return DRWAV_NO_NETWORK;
4886 #endif
4887 #ifdef ENETUNREACH
4888 case ENETUNREACH: return DRWAV_NO_NETWORK;
4889 #endif
4890 #ifdef ENETRESET
4891 case ENETRESET: return DRWAV_NO_NETWORK;
4892 #endif
4893 #ifdef ECONNABORTED
4894 case ECONNABORTED: return DRWAV_NO_NETWORK;
4895 #endif
4896 #ifdef ECONNRESET
4897 case ECONNRESET: return DRWAV_CONNECTION_RESET;
4898 #endif
4899 #ifdef ENOBUFS
4900 case ENOBUFS: return DRWAV_NO_SPACE;
4901 #endif
4902 #ifdef EISCONN
4903 case EISCONN: return DRWAV_ALREADY_CONNECTED;
4904 #endif
4905 #ifdef ENOTCONN
4906 case ENOTCONN: return DRWAV_NOT_CONNECTED;
4907 #endif
4908 #ifdef ESHUTDOWN
4909 case ESHUTDOWN: return DRWAV_ERROR;
4910 #endif
4911 #ifdef ETOOMANYREFS
4912 case ETOOMANYREFS: return DRWAV_ERROR;
4913 #endif
4914 #ifdef ETIMEDOUT
4915 case ETIMEDOUT: return DRWAV_TIMEOUT;
4916 #endif
4917 #ifdef ECONNREFUSED
4918 case ECONNREFUSED: return DRWAV_CONNECTION_REFUSED;
4919 #endif
4920 #ifdef EHOSTDOWN
4921 case EHOSTDOWN: return DRWAV_NO_HOST;
4922 #endif
4923 #ifdef EHOSTUNREACH
4924 case EHOSTUNREACH: return DRWAV_NO_HOST;
4925 #endif
4926 #ifdef EALREADY
4927 case EALREADY: return DRWAV_IN_PROGRESS;
4928 #endif
4929 #ifdef EINPROGRESS
4930 case EINPROGRESS: return DRWAV_IN_PROGRESS;
4931 #endif
4932 #ifdef ESTALE
4933 case ESTALE: return DRWAV_INVALID_FILE;
4934 #endif
4935 #ifdef EUCLEAN
4936 case EUCLEAN: return DRWAV_ERROR;
4937 #endif
4938 #ifdef ENOTNAM
4939 case ENOTNAM: return DRWAV_ERROR;
4940 #endif
4941 #ifdef ENAVAIL
4942 case ENAVAIL: return DRWAV_ERROR;
4943 #endif
4944 #ifdef EISNAM
4945 case EISNAM: return DRWAV_ERROR;
4946 #endif
4947 #ifdef EREMOTEIO
4948 case EREMOTEIO: return DRWAV_IO_ERROR;
4949 #endif
4950 #ifdef EDQUOT
4951 case EDQUOT: return DRWAV_NO_SPACE;
4952 #endif
4953 #ifdef ENOMEDIUM
4954 case ENOMEDIUM: return DRWAV_DOES_NOT_EXIST;
4955 #endif
4956 #ifdef EMEDIUMTYPE
4957 case EMEDIUMTYPE: return DRWAV_ERROR;
4958 #endif
4959 #ifdef ECANCELED
4960 case ECANCELED: return DRWAV_CANCELLED;
4961 #endif
4962 #ifdef ENOKEY
4963 case ENOKEY: return DRWAV_ERROR;
4964 #endif
4965 #ifdef EKEYEXPIRED
4966 case EKEYEXPIRED: return DRWAV_ERROR;
4967 #endif
4968 #ifdef EKEYREVOKED
4969 case EKEYREVOKED: return DRWAV_ERROR;
4970 #endif
4971 #ifdef EKEYREJECTED
4972 case EKEYREJECTED: return DRWAV_ERROR;
4973 #endif
4974 #ifdef EOWNERDEAD
4975 case EOWNERDEAD: return DRWAV_ERROR;
4976 #endif
4977 #ifdef ENOTRECOVERABLE
4978 case ENOTRECOVERABLE: return DRWAV_ERROR;
4979 #endif
4980 #ifdef ERFKILL
4981 case ERFKILL: return DRWAV_ERROR;
4982 #endif
4983 #ifdef EHWPOISON
4984 case EHWPOISON: return DRWAV_ERROR;
4985 #endif
4986 default: return DRWAV_ERROR;
4987 }
4988}
4989/* End Errno */
4990
4991/* fopen */
4992DRWAV_PRIVATE drwav_result drwav_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
4993{
4994#if defined(_MSC_VER) && _MSC_VER >= 1400
4995 errno_t err;
4996#endif
4997
4998 if (ppFile != NULL) {
4999 *ppFile = NULL; /* Safety. */
5000 }
5001
5002 if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
5003 return DRWAV_INVALID_ARGS;
5004 }
5005
5006#if defined(_MSC_VER) && _MSC_VER >= 1400
5007 err = fopen_s(ppFile, pFilePath, pOpenMode);
5008 if (err != 0) {
5009 return drwav_result_from_errno(err);
5010 }
5011#else
5012#if defined(_WIN32) || defined(__APPLE__)
5013 *ppFile = fopen(pFilePath, pOpenMode);
5014#else
5015 #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE)
5016 *ppFile = fopen64(pFilePath, pOpenMode);
5017 #else
5018 *ppFile = fopen(pFilePath, pOpenMode);
5019 #endif
5020#endif
5021 if (*ppFile == NULL) {
5022 drwav_result result = drwav_result_from_errno(errno);
5023 if (result == DRWAV_SUCCESS) {
5024 result = DRWAV_ERROR; /* Just a safety check to make sure we never ever return success when pFile == NULL. */
5025 }
5026
5027 return result;
5028 }
5029#endif
5030
5031 return DRWAV_SUCCESS;
5032}
5033
5034/*
5035_wfopen() isn't always available in all compilation environments.
5036
5037 * Windows only.
5038 * MSVC seems to support it universally as far back as VC6 from what I can tell (haven't checked further back).
5039 * MinGW-64 (both 32- and 64-bit) seems to support it.
5040 * MinGW wraps it in !defined(__STRICT_ANSI__).
5041 * OpenWatcom wraps it in !defined(_NO_EXT_KEYS).
5042
5043This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs()
5044fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support.
5045*/
5046#if defined(_WIN32)
5047 #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS))
5048 #define DRWAV_HAS_WFOPEN
5049 #endif
5050#endif
5051
5052#ifndef DR_WAV_NO_WCHAR
5053DRWAV_PRIVATE drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drwav_allocation_callbacks* pAllocationCallbacks)
5054{
5055 if (ppFile != NULL) {
5056 *ppFile = NULL; /* Safety. */
5057 }
5058
5059 if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
5060 return DRWAV_INVALID_ARGS;
5061 }
5062
5063#if defined(DRWAV_HAS_WFOPEN)
5064 {
5065 /* Use _wfopen() on Windows. */
5066 #if defined(_MSC_VER) && _MSC_VER >= 1400
5067 errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode);
5068 if (err != 0) {
5069 return drwav_result_from_errno(err);
5070 }
5071 #else
5072 *ppFile = _wfopen(pFilePath, pOpenMode);
5073 if (*ppFile == NULL) {
5074 return drwav_result_from_errno(errno);
5075 }
5076 #endif
5077 (void)pAllocationCallbacks;
5078 }
5079#else
5080 /*
5081 Use fopen() on anything other than Windows. Requires a conversion. This is annoying because
5082 fopen() is locale specific. The only real way I can think of to do this is with wcsrtombs(). Note
5083 that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for
5084 maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler
5085 error I'll look into improving compatibility.
5086 */
5087
5088 /*
5089 Some compilers don't support wchar_t or wcsrtombs() which we're using below. In this case we just
5090 need to abort with an error. If you encounter a compiler lacking such support, add it to this list
5091 and submit a bug report and it'll be added to the library upstream.
5092 */
5093 #if defined(__DJGPP__)
5094 {
5095 /* Nothing to do here. This will fall through to the error check below. */
5096 }
5097 #else
5098 {
5099 mbstate_t mbs;
5100 size_t lenMB;
5101 const wchar_t* pFilePathTemp = pFilePath;
5102 char* pFilePathMB = NULL;
5103 char pOpenModeMB[32] = {0};
5104
5105 /* Get the length first. */
5106 DRWAV_ZERO_OBJECT(&mbs);
5107 lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs);
5108 if (lenMB == (size_t)-1) {
5109 return drwav_result_from_errno(errno);
5110 }
5111
5112 pFilePathMB = (char*)drwav__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks);
5113 if (pFilePathMB == NULL) {
5114 return DRWAV_OUT_OF_MEMORY;
5115 }
5116
5117 pFilePathTemp = pFilePath;
5118 DRWAV_ZERO_OBJECT(&mbs);
5119 wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs);
5120
5121 /* The open mode should always consist of ASCII characters so we should be able to do a trivial conversion. */
5122 {
5123 size_t i = 0;
5124 for (;;) {
5125 if (pOpenMode[i] == 0) {
5126 pOpenModeMB[i] = '\0';
5127 break;
5128 }
5129
5130 pOpenModeMB[i] = (char)pOpenMode[i];
5131 i += 1;
5132 }
5133 }
5134
5135 *ppFile = fopen(pFilePathMB, pOpenModeMB);
5136
5137 drwav__free_from_callbacks(pFilePathMB, pAllocationCallbacks);
5138 }
5139 #endif
5140
5141 if (*ppFile == NULL) {
5142 return DRWAV_ERROR;
5143 }
5144#endif
5145
5146 return DRWAV_SUCCESS;
5147}
5148#endif
5149/* End fopen */
5150
5151
5152DRWAV_PRIVATE size_t drwav__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead)
5153{
5154 return fread(pBufferOut, 1, bytesToRead, (FILE*)pUserData);
5155}
5156
5157DRWAV_PRIVATE size_t drwav__on_write_stdio(void* pUserData, const void* pData, size_t bytesToWrite)
5158{
5159 return fwrite(pData, 1, bytesToWrite, (FILE*)pUserData);
5160}
5161
5162DRWAV_PRIVATE drwav_bool32 drwav__on_seek_stdio(void* pUserData, int offset, drwav_seek_origin origin)
5163{
5164 return fseek((FILE*)pUserData, offset, (origin == drwav_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
5165}
5166
5167DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks)
5168{
5169 return drwav_init_file_ex(pWav, filename, NULL, NULL, 0, pAllocationCallbacks);
5170}
5171
5172
5173DRWAV_PRIVATE drwav_bool32 drwav_init_file__internal_FILE(drwav* pWav, FILE* pFile, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
5174{
5175 drwav_bool32 result;
5176
5177 result = drwav_preinit(pWav, drwav__on_read_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
5178 if (result != DRWAV_TRUE) {
5179 fclose(pFile);
5180 return result;
5181 }
5182
5183 result = drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
5184 if (result != DRWAV_TRUE) {
5185 fclose(pFile);
5186 return result;
5187 }
5188
5189 return DRWAV_TRUE;
5190}
5191
5192DRWAV_API drwav_bool32 drwav_init_file_ex(drwav* pWav, const char* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
5193{
5194 FILE* pFile;
5195 if (drwav_fopen(&pFile, filename, "rb") != DRWAV_SUCCESS) {
5196 return DRWAV_FALSE;
5197 }
5198
5199 /* This takes ownership of the FILE* object. */
5200 return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks);
5201}
5202
5203#ifndef DR_WAV_NO_WCHAR
5204DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks)
5205{
5206 return drwav_init_file_ex_w(pWav, filename, NULL, NULL, 0, pAllocationCallbacks);
5207}
5208
5209DRWAV_API drwav_bool32 drwav_init_file_ex_w(drwav* pWav, const wchar_t* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
5210{
5211 FILE* pFile;
5212 if (drwav_wfopen(&pFile, filename, L"rb", pAllocationCallbacks) != DRWAV_SUCCESS) {
5213 return DRWAV_FALSE;
5214 }
5215
5216 /* This takes ownership of the FILE* object. */
5217 return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks);
5218}
5219#endif
5220
5221DRWAV_API drwav_bool32 drwav_init_file_with_metadata(drwav* pWav, const char* filename, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
5222{
5223 FILE* pFile;
5224 if (drwav_fopen(&pFile, filename, "rb") != DRWAV_SUCCESS) {
5225 return DRWAV_FALSE;
5226 }
5227
5228 /* This takes ownership of the FILE* object. */
5229 return drwav_init_file__internal_FILE(pWav, pFile, NULL, NULL, flags | DRWAV_WITH_METADATA, pAllocationCallbacks);
5230}
5231
5232#ifndef DR_WAV_NO_WCHAR
5233DRWAV_API drwav_bool32 drwav_init_file_with_metadata_w(drwav* pWav, const wchar_t* filename, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
5234{
5235 FILE* pFile;
5236 if (drwav_wfopen(&pFile, filename, L"rb", pAllocationCallbacks) != DRWAV_SUCCESS) {
5237 return DRWAV_FALSE;
5238 }
5239
5240 /* This takes ownership of the FILE* object. */
5241 return drwav_init_file__internal_FILE(pWav, pFile, NULL, NULL, flags | DRWAV_WITH_METADATA, pAllocationCallbacks);
5242}
5243#endif
5244
5245
5246DRWAV_PRIVATE drwav_bool32 drwav_init_file_write__internal_FILE(drwav* pWav, FILE* pFile, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
5247{
5248 drwav_bool32 result;
5249
5250 result = drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
5251 if (result != DRWAV_TRUE) {
5252 fclose(pFile);
5253 return result;
5254 }
5255
5256 result = drwav_init_write__internal(pWav, pFormat, totalSampleCount);
5257 if (result != DRWAV_TRUE) {
5258 fclose(pFile);
5259 return result;
5260 }
5261
5262 return DRWAV_TRUE;
5263}
5264
5265DRWAV_PRIVATE drwav_bool32 drwav_init_file_write__internal(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
5266{
5267 FILE* pFile;
5268 if (drwav_fopen(&pFile, filename, "wb") != DRWAV_SUCCESS) {
5269 return DRWAV_FALSE;
5270 }
5271
5272 /* This takes ownership of the FILE* object. */
5273 return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks);
5274}
5275
5276#ifndef DR_WAV_NO_WCHAR
5277DRWAV_PRIVATE drwav_bool32 drwav_init_file_write_w__internal(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
5278{
5279 FILE* pFile;
5280 if (drwav_wfopen(&pFile, filename, L"wb", pAllocationCallbacks) != DRWAV_SUCCESS) {
5281 return DRWAV_FALSE;
5282 }
5283
5284 /* This takes ownership of the FILE* object. */
5285 return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks);
5286}
5287#endif
5288
5289DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks)
5290{
5291 return drwav_init_file_write__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
5292}
5293
5294DRWAV_API drwav_bool32 drwav_init_file_write_sequential(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks)
5295{
5296 return drwav_init_file_write__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
5297}
5298
5299DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks)
5300{
5301 if (pFormat == NULL) {
5302 return DRWAV_FALSE;
5303 }
5304
5305 return drwav_init_file_write_sequential(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
5306}
5307
5308#ifndef DR_WAV_NO_WCHAR
5309DRWAV_API drwav_bool32 drwav_init_file_write_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks)
5310{
5311 return drwav_init_file_write_w__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
5312}
5313
5314DRWAV_API drwav_bool32 drwav_init_file_write_sequential_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks)
5315{
5316 return drwav_init_file_write_w__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
5317}
5318
5319DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks)
5320{
5321 if (pFormat == NULL) {
5322 return DRWAV_FALSE;
5323 }
5324
5325 return drwav_init_file_write_sequential_w(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
5326}
5327#endif
5328#endif /* DR_WAV_NO_STDIO */
5329
5330
5331DRWAV_PRIVATE size_t drwav__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead)
5332{
5333 drwav* pWav = (drwav*)pUserData;
5334 size_t bytesRemaining;
5335
5336 DRWAV_ASSERT(pWav != NULL);
5337 DRWAV_ASSERT(pWav->memoryStream.dataSize >= pWav->memoryStream.currentReadPos);
5338
5339 bytesRemaining = pWav->memoryStream.dataSize - pWav->memoryStream.currentReadPos;
5340 if (bytesToRead > bytesRemaining) {
5341 bytesToRead = bytesRemaining;
5342 }
5343
5344 if (bytesToRead > 0) {
5345 DRWAV_COPY_MEMORY(pBufferOut, pWav->memoryStream.data + pWav->memoryStream.currentReadPos, bytesToRead);
5346 pWav->memoryStream.currentReadPos += bytesToRead;
5347 }
5348
5349 return bytesToRead;
5350}
5351
5352DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_seek_origin origin)
5353{
5354 drwav* pWav = (drwav*)pUserData;
5355 DRWAV_ASSERT(pWav != NULL);
5356
5357 if (origin == drwav_seek_origin_current) {
5358 if (offset > 0) {
5359 if (pWav->memoryStream.currentReadPos + offset > pWav->memoryStream.dataSize) {
5360 return DRWAV_FALSE; /* Trying to seek too far forward. */
5361 }
5362 } else {
5363 if (pWav->memoryStream.currentReadPos < (size_t)-offset) {
5364 return DRWAV_FALSE; /* Trying to seek too far backwards. */
5365 }
5366 }
5367
5368 /* This will never underflow thanks to the clamps above. */
5369 pWav->memoryStream.currentReadPos += offset;
5370 } else {
5371 if ((drwav_uint32)offset <= pWav->memoryStream.dataSize) {
5372 pWav->memoryStream.currentReadPos = offset;
5373 } else {
5374 return DRWAV_FALSE; /* Trying to seek too far forward. */
5375 }
5376 }
5377
5378 return DRWAV_TRUE;
5379}
5380
5381DRWAV_PRIVATE size_t drwav__on_write_memory(void* pUserData, const void* pDataIn, size_t bytesToWrite)
5382{
5383 drwav* pWav = (drwav*)pUserData;
5384 size_t bytesRemaining;
5385
5386 DRWAV_ASSERT(pWav != NULL);
5387 DRWAV_ASSERT(pWav->memoryStreamWrite.dataCapacity >= pWav->memoryStreamWrite.currentWritePos);
5388
5389 bytesRemaining = pWav->memoryStreamWrite.dataCapacity - pWav->memoryStreamWrite.currentWritePos;
5390 if (bytesRemaining < bytesToWrite) {
5391 /* Need to reallocate. */
5392 void* pNewData;
5393 size_t newDataCapacity = (pWav->memoryStreamWrite.dataCapacity == 0) ? 256 : pWav->memoryStreamWrite.dataCapacity * 2;
5394
5395 /* If doubling wasn't enough, just make it the minimum required size to write the data. */
5396 if ((newDataCapacity - pWav->memoryStreamWrite.currentWritePos) < bytesToWrite) {
5397 newDataCapacity = pWav->memoryStreamWrite.currentWritePos + bytesToWrite;
5398 }
5399
5400 pNewData = drwav__realloc_from_callbacks(*pWav->memoryStreamWrite.ppData, newDataCapacity, pWav->memoryStreamWrite.dataCapacity, &pWav->allocationCallbacks);
5401 if (pNewData == NULL) {
5402 return 0;
5403 }
5404
5405 *pWav->memoryStreamWrite.ppData = pNewData;
5406 pWav->memoryStreamWrite.dataCapacity = newDataCapacity;
5407 }
5408
5409 DRWAV_COPY_MEMORY(((drwav_uint8*)(*pWav->memoryStreamWrite.ppData)) + pWav->memoryStreamWrite.currentWritePos, pDataIn, bytesToWrite);
5410
5411 pWav->memoryStreamWrite.currentWritePos += bytesToWrite;
5412 if (pWav->memoryStreamWrite.dataSize < pWav->memoryStreamWrite.currentWritePos) {
5413 pWav->memoryStreamWrite.dataSize = pWav->memoryStreamWrite.currentWritePos;
5414 }
5415
5416 *pWav->memoryStreamWrite.pDataSize = pWav->memoryStreamWrite.dataSize;
5417
5418 return bytesToWrite;
5419}
5420
5421DRWAV_PRIVATE drwav_bool32 drwav__on_seek_memory_write(void* pUserData, int offset, drwav_seek_origin origin)
5422{
5423 drwav* pWav = (drwav*)pUserData;
5424 DRWAV_ASSERT(pWav != NULL);
5425
5426 if (origin == drwav_seek_origin_current) {
5427 if (offset > 0) {
5428 if (pWav->memoryStreamWrite.currentWritePos + offset > pWav->memoryStreamWrite.dataSize) {
5429 offset = (int)(pWav->memoryStreamWrite.dataSize - pWav->memoryStreamWrite.currentWritePos); /* Trying to seek too far forward. */
5430 }
5431 } else {
5432 if (pWav->memoryStreamWrite.currentWritePos < (size_t)-offset) {
5433 offset = -(int)pWav->memoryStreamWrite.currentWritePos; /* Trying to seek too far backwards. */
5434 }
5435 }
5436
5437 /* This will never underflow thanks to the clamps above. */
5438 pWav->memoryStreamWrite.currentWritePos += offset;
5439 } else {
5440 if ((drwav_uint32)offset <= pWav->memoryStreamWrite.dataSize) {
5441 pWav->memoryStreamWrite.currentWritePos = offset;
5442 } else {
5443 pWav->memoryStreamWrite.currentWritePos = pWav->memoryStreamWrite.dataSize; /* Trying to seek too far forward. */
5444 }
5445 }
5446
5447 return DRWAV_TRUE;
5448}
5449
5450DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks)
5451{
5452 return drwav_init_memory_ex(pWav, data, dataSize, NULL, NULL, 0, pAllocationCallbacks);
5453}
5454
5455DRWAV_API drwav_bool32 drwav_init_memory_ex(drwav* pWav, const void* data, size_t dataSize, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
5456{
5457 if (data == NULL || dataSize == 0) {
5458 return DRWAV_FALSE;
5459 }
5460
5461 if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, pWav, pAllocationCallbacks)) {
5462 return DRWAV_FALSE;
5463 }
5464
5465 pWav->memoryStream.data = (const drwav_uint8*)data;
5466 pWav->memoryStream.dataSize = dataSize;
5467 pWav->memoryStream.currentReadPos = 0;
5468
5469 return drwav_init__internal(pWav, onChunk, pChunkUserData, flags);
5470}
5471
5472DRWAV_API drwav_bool32 drwav_init_memory_with_metadata(drwav* pWav, const void* data, size_t dataSize, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
5473{
5474 if (data == NULL || dataSize == 0) {
5475 return DRWAV_FALSE;
5476 }
5477
5478 if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, pWav, pAllocationCallbacks)) {
5479 return DRWAV_FALSE;
5480 }
5481
5482 pWav->memoryStream.data = (const drwav_uint8*)data;
5483 pWav->memoryStream.dataSize = dataSize;
5484 pWav->memoryStream.currentReadPos = 0;
5485
5486 return drwav_init__internal(pWav, NULL, NULL, flags | DRWAV_WITH_METADATA);
5487}
5488
5489
5490DRWAV_PRIVATE drwav_bool32 drwav_init_memory_write__internal(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
5491{
5492 if (ppData == NULL || pDataSize == NULL) {
5493 return DRWAV_FALSE;
5494 }
5495
5496 *ppData = NULL; /* Important because we're using realloc()! */
5497 *pDataSize = 0;
5498
5499 if (!drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_memory, drwav__on_seek_memory_write, pWav, pAllocationCallbacks)) {
5500 return DRWAV_FALSE;
5501 }
5502
5503 pWav->memoryStreamWrite.ppData = ppData;
5504 pWav->memoryStreamWrite.pDataSize = pDataSize;
5505 pWav->memoryStreamWrite.dataSize = 0;
5506 pWav->memoryStreamWrite.dataCapacity = 0;
5507 pWav->memoryStreamWrite.currentWritePos = 0;
5508
5509 return drwav_init_write__internal(pWav, pFormat, totalSampleCount);
5510}
5511
5512DRWAV_API drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks)
5513{
5514 return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
5515}
5516
5517DRWAV_API drwav_bool32 drwav_init_memory_write_sequential(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks)
5518{
5519 return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks);
5520}
5521
5522DRWAV_API drwav_bool32 drwav_init_memory_write_sequential_pcm_frames(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks)
5523{
5524 if (pFormat == NULL) {
5525 return DRWAV_FALSE;
5526 }
5527
5528 return drwav_init_memory_write_sequential(pWav, ppData, pDataSize, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
5529}
5530
5531
5532
5533DRWAV_API drwav_result drwav_uninit(drwav* pWav)
5534{
5535 drwav_result result = DRWAV_SUCCESS;
5536
5537 if (pWav == NULL) {
5538 return DRWAV_INVALID_ARGS;
5539 }
5540
5541 /*
5542 If the drwav object was opened in write mode we'll need to finalize a few things:
5543 - Make sure the "data" chunk is aligned to 16-bits for RIFF containers, or 64 bits for W64 containers.
5544 - Set the size of the "data" chunk.
5545 */
5546 if (pWav->onWrite != NULL) {
5547 drwav_uint32 paddingSize = 0;
5548
5549 /* Padding. Do not adjust pWav->dataChunkDataSize - this should not include the padding. */
5550 if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) {
5551 paddingSize = drwav__chunk_padding_size_riff(pWav->dataChunkDataSize);
5552 } else {
5553 paddingSize = drwav__chunk_padding_size_w64(pWav->dataChunkDataSize);
5554 }
5555
5556 if (paddingSize > 0) {
5557 drwav_uint64 paddingData = 0;
5558 drwav__write(pWav, &paddingData, paddingSize); /* Byte order does not matter for this. */
5559 }
5560
5561 /*
5562 Chunk sizes. When using sequential mode, these will have been filled in at initialization time. We only need
5563 to do this when using non-sequential mode.
5564 */
5565 if (pWav->onSeek && !pWav->isSequentialWrite) {
5566 if (pWav->container == drwav_container_riff) {
5567 /* The "RIFF" chunk size. */
5568 if (pWav->onSeek(pWav->pUserData, 4, drwav_seek_origin_start)) {
5569 drwav_uint32 riffChunkSize = drwav__riff_chunk_size_riff(pWav->dataChunkDataSize, pWav->pMetadata, pWav->metadataCount);
5570 drwav__write_u32ne_to_le(pWav, riffChunkSize);
5571 }
5572
5573 /* The "data" chunk size. */
5574 if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 4, drwav_seek_origin_start)) {
5575 drwav_uint32 dataChunkSize = drwav__data_chunk_size_riff(pWav->dataChunkDataSize);
5576 drwav__write_u32ne_to_le(pWav, dataChunkSize);
5577 }
5578 } else if (pWav->container == drwav_container_w64) {
5579 /* The "RIFF" chunk size. */
5580 if (pWav->onSeek(pWav->pUserData, 16, drwav_seek_origin_start)) {
5581 drwav_uint64 riffChunkSize = drwav__riff_chunk_size_w64(pWav->dataChunkDataSize);
5582 drwav__write_u64ne_to_le(pWav, riffChunkSize);
5583 }
5584
5585 /* The "data" chunk size. */
5586 if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos - 8, drwav_seek_origin_start)) {
5587 drwav_uint64 dataChunkSize = drwav__data_chunk_size_w64(pWav->dataChunkDataSize);
5588 drwav__write_u64ne_to_le(pWav, dataChunkSize);
5589 }
5590 } else if (pWav->container == drwav_container_rf64) {
5591 /* We only need to update the ds64 chunk. The "RIFF" and "data" chunks always have their sizes set to 0xFFFFFFFF for RF64. */
5592 int ds64BodyPos = 12 + 8;
5593
5594 /* The "RIFF" chunk size. */
5595 if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, drwav_seek_origin_start)) {
5596 drwav_uint64 riffChunkSize = drwav__riff_chunk_size_rf64(pWav->dataChunkDataSize, pWav->pMetadata, pWav->metadataCount);
5597 drwav__write_u64ne_to_le(pWav, riffChunkSize);
5598 }
5599
5600 /* The "data" chunk size. */
5601 if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 8, drwav_seek_origin_start)) {
5602 drwav_uint64 dataChunkSize = drwav__data_chunk_size_rf64(pWav->dataChunkDataSize);
5603 drwav__write_u64ne_to_le(pWav, dataChunkSize);
5604 }
5605 }
5606 }
5607
5608 /* Validation for sequential mode. */
5609 if (pWav->isSequentialWrite) {
5610 if (pWav->dataChunkDataSize != pWav->dataChunkDataSizeTargetWrite) {
5611 result = DRWAV_INVALID_FILE;
5612 }
5613 }
5614 } else {
5615 drwav_free(pWav->pMetadata, &pWav->allocationCallbacks);
5616 }
5617
5618#ifndef DR_WAV_NO_STDIO
5619 /*
5620 If we opened the file with drwav_open_file() we will want to close the file handle. We can know whether or not drwav_open_file()
5621 was used by looking at the onRead and onSeek callbacks.
5622 */
5623 if (pWav->onRead == drwav__on_read_stdio || pWav->onWrite == drwav__on_write_stdio) {
5624 fclose((FILE*)pWav->pUserData);
5625 }
5626#endif
5627
5628 return result;
5629}
5630
5631
5632
5633DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut)
5634{
5635 size_t bytesRead;
5636 drwav_uint32 bytesPerFrame;
5637
5638 if (pWav == NULL || bytesToRead == 0) {
5639 return 0; /* Invalid args. */
5640 }
5641
5642 if (bytesToRead > pWav->bytesRemaining) {
5643 bytesToRead = (size_t)pWav->bytesRemaining;
5644 }
5645
5646 if (bytesToRead == 0) {
5647 return 0; /* At end. */
5648 }
5649
5650 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
5651 if (bytesPerFrame == 0) {
5652 return 0; /* Could not determine the bytes per frame. */
5653 }
5654
5655 if (pBufferOut != NULL) {
5656 bytesRead = pWav->onRead(pWav->pUserData, pBufferOut, bytesToRead);
5657 } else {
5658 /* We need to seek. If we fail, we need to read-and-discard to make sure we get a good byte count. */
5659 bytesRead = 0;
5660 while (bytesRead < bytesToRead) {
5661 size_t bytesToSeek = (bytesToRead - bytesRead);
5662 if (bytesToSeek > 0x7FFFFFFF) {
5663 bytesToSeek = 0x7FFFFFFF;
5664 }
5665
5666 if (pWav->onSeek(pWav->pUserData, (int)bytesToSeek, drwav_seek_origin_current) == DRWAV_FALSE) {
5667 break;
5668 }
5669
5670 bytesRead += bytesToSeek;
5671 }
5672
5673 /* When we get here we may need to read-and-discard some data. */
5674 while (bytesRead < bytesToRead) {
5675 drwav_uint8 buffer[4096];
5676 size_t bytesSeeked;
5677 size_t bytesToSeek = (bytesToRead - bytesRead);
5678 if (bytesToSeek > sizeof(buffer)) {
5679 bytesToSeek = sizeof(buffer);
5680 }
5681
5682 bytesSeeked = pWav->onRead(pWav->pUserData, buffer, bytesToSeek);
5683 bytesRead += bytesSeeked;
5684
5685 if (bytesSeeked < bytesToSeek) {
5686 break; /* Reached the end. */
5687 }
5688 }
5689 }
5690
5691 pWav->readCursorInPCMFrames += bytesRead / bytesPerFrame;
5692
5693 pWav->bytesRemaining -= bytesRead;
5694 return bytesRead;
5695}
5696
5697
5698
5699DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut)
5700{
5701 drwav_uint32 bytesPerFrame;
5702 drwav_uint64 bytesToRead; /* Intentionally uint64 instead of size_t so we can do a check that we're not reading too much on 32-bit builds. */
5703 drwav_uint64 framesRemainingInFile;
5704
5705 if (pWav == NULL || framesToRead == 0) {
5706 return 0;
5707 }
5708
5709 /* Cannot use this function for compressed formats. */
5710 if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
5711 return 0;
5712 }
5713
5714 framesRemainingInFile = pWav->totalPCMFrameCount - pWav->readCursorInPCMFrames;
5715 if (framesToRead > framesRemainingInFile) {
5716 framesToRead = framesRemainingInFile;
5717 }
5718
5719 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
5720 if (bytesPerFrame == 0) {
5721 return 0;
5722 }
5723
5724 /* Don't try to read more samples than can potentially fit in the output buffer. */
5725 bytesToRead = framesToRead * bytesPerFrame;
5726 if (bytesToRead > DRWAV_SIZE_MAX) {
5727 bytesToRead = (DRWAV_SIZE_MAX / bytesPerFrame) * bytesPerFrame; /* Round the number of bytes to read to a clean frame boundary. */
5728 }
5729
5730 /*
5731 Doing an explicit check here just to make it clear that we don't want to be attempt to read anything if there's no bytes to read. There
5732 *could* be a time where it evaluates to 0 due to overflowing.
5733 */
5734 if (bytesToRead == 0) {
5735 return 0;
5736 }
5737
5738 return drwav_read_raw(pWav, (size_t)bytesToRead, pBufferOut) / bytesPerFrame;
5739}
5740
5741DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut)
5742{
5743 drwav_uint64 framesRead = drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut);
5744
5745 if (pBufferOut != NULL) {
5746 drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
5747 if (bytesPerFrame == 0) {
5748 return 0; /* Could not get the bytes per frame which means bytes per sample cannot be determined and we don't know how to byte swap. */
5749 }
5750
5751 drwav__bswap_samples(pBufferOut, framesRead*pWav->channels, bytesPerFrame/pWav->channels);
5752 }
5753
5754 return framesRead;
5755}
5756
5757DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut)
5758{
5759 drwav_uint64 framesRead = 0;
5760
5761 if (drwav_is_container_be(pWav->container)) {
5762 /*
5763 Special case for AIFF. AIFF is a big-endian encoded format, but it supports a format that is
5764 PCM in little-endian encoding. In this case, we fall through this branch and treate it as
5765 little-endian.
5766 */
5767 if (pWav->container != drwav_container_aiff || pWav->aiff.isLE == DRWAV_FALSE) {
5768 if (drwav__is_little_endian()) {
5769 framesRead = drwav_read_pcm_frames_be(pWav, framesToRead, pBufferOut);
5770 } else {
5771 framesRead = drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut);
5772 }
5773
5774 goto post_process;
5775 }
5776 }
5777
5778 /* Getting here means the data should be considered little-endian. */
5779 if (drwav__is_little_endian()) {
5780 framesRead = drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut);
5781 } else {
5782 framesRead = drwav_read_pcm_frames_be(pWav, framesToRead, pBufferOut);
5783 }
5784
5785 /*
5786 Here is where we check if we need to do a signed/unsigned conversion for AIFF. The reason we need to do this
5787 is because dr_wav always assumes an 8-bit sample is unsigned, whereas AIFF can have signed 8-bit formats.
5788 */
5789 post_process:
5790 {
5791 if (pWav->container == drwav_container_aiff && pWav->bitsPerSample == 8 && pWav->aiff.isUnsigned == DRWAV_FALSE) {
5792 if (pBufferOut != NULL) {
5793 drwav_uint64 iSample;
5794
5795 for (iSample = 0; iSample < framesRead * pWav->channels; iSample += 1) {
5796 ((drwav_uint8*)pBufferOut)[iSample] += 128;
5797 }
5798 }
5799 }
5800 }
5801
5802 return framesRead;
5803}
5804
5805
5806
5807DRWAV_PRIVATE drwav_bool32 drwav_seek_to_first_pcm_frame(drwav* pWav)
5808{
5809 if (pWav->onWrite != NULL) {
5810 return DRWAV_FALSE; /* No seeking in write mode. */
5811 }
5812
5813 if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, drwav_seek_origin_start)) {
5814 return DRWAV_FALSE;
5815 }
5816
5817 if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
5818 /* Cached data needs to be cleared for compressed formats. */
5819 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
5820 DRWAV_ZERO_OBJECT(&pWav->msadpcm);
5821 } else if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
5822 DRWAV_ZERO_OBJECT(&pWav->ima);
5823 } else {
5824 DRWAV_ASSERT(DRWAV_FALSE); /* If this assertion is triggered it means I've implemented a new compressed format but forgot to add a branch for it here. */
5825 }
5826 }
5827
5828 pWav->readCursorInPCMFrames = 0;
5829 pWav->bytesRemaining = pWav->dataChunkDataSize;
5830
5831 return DRWAV_TRUE;
5832}
5833
5834DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex)
5835{
5836 /* Seeking should be compatible with wave files > 2GB. */
5837
5838 if (pWav == NULL || pWav->onSeek == NULL) {
5839 return DRWAV_FALSE;
5840 }
5841
5842 /* No seeking in write mode. */
5843 if (pWav->onWrite != NULL) {
5844 return DRWAV_FALSE;
5845 }
5846
5847 /* If there are no samples, just return DRWAV_TRUE without doing anything. */
5848 if (pWav->totalPCMFrameCount == 0) {
5849 return DRWAV_TRUE;
5850 }
5851
5852 /* Make sure the sample is clamped. */
5853 if (targetFrameIndex > pWav->totalPCMFrameCount) {
5854 targetFrameIndex = pWav->totalPCMFrameCount;
5855 }
5856
5857 /*
5858 For compressed formats we just use a slow generic seek. If we are seeking forward we just seek forward. If we are going backwards we need
5859 to seek back to the start.
5860 */
5861 if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
5862 /* TODO: This can be optimized. */
5863
5864 /*
5865 If we're seeking forward it's simple - just keep reading samples until we hit the sample we're requesting. If we're seeking backwards,
5866 we first need to seek back to the start and then just do the same thing as a forward seek.
5867 */
5868 if (targetFrameIndex < pWav->readCursorInPCMFrames) {
5869 if (!drwav_seek_to_first_pcm_frame(pWav)) {
5870 return DRWAV_FALSE;
5871 }
5872 }
5873
5874 if (targetFrameIndex > pWav->readCursorInPCMFrames) {
5875 drwav_uint64 offsetInFrames = targetFrameIndex - pWav->readCursorInPCMFrames;
5876
5877 drwav_int16 devnull[2048];
5878 while (offsetInFrames > 0) {
5879 drwav_uint64 framesRead = 0;
5880 drwav_uint64 framesToRead = offsetInFrames;
5881 if (framesToRead > drwav_countof(devnull)/pWav->channels) {
5882 framesToRead = drwav_countof(devnull)/pWav->channels;
5883 }
5884
5885 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
5886 framesRead = drwav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, devnull);
5887 } else if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
5888 framesRead = drwav_read_pcm_frames_s16__ima(pWav, framesToRead, devnull);
5889 } else {
5890 DRWAV_ASSERT(DRWAV_FALSE); /* If this assertion is triggered it means I've implemented a new compressed format but forgot to add a branch for it here. */
5891 }
5892
5893 if (framesRead != framesToRead) {
5894 return DRWAV_FALSE;
5895 }
5896
5897 offsetInFrames -= framesRead;
5898 }
5899 }
5900 } else {
5901 drwav_uint64 totalSizeInBytes;
5902 drwav_uint64 currentBytePos;
5903 drwav_uint64 targetBytePos;
5904 drwav_uint64 offset;
5905 drwav_uint32 bytesPerFrame;
5906
5907 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
5908 if (bytesPerFrame == 0) {
5909 return DRWAV_FALSE; /* Not able to calculate offset. */
5910 }
5911
5912 totalSizeInBytes = pWav->totalPCMFrameCount * bytesPerFrame;
5913 /*DRWAV_ASSERT(totalSizeInBytes >= pWav->bytesRemaining);*/
5914
5915 currentBytePos = totalSizeInBytes - pWav->bytesRemaining;
5916 targetBytePos = targetFrameIndex * bytesPerFrame;
5917
5918 if (currentBytePos < targetBytePos) {
5919 /* Offset forwards. */
5920 offset = (targetBytePos - currentBytePos);
5921 } else {
5922 /* Offset backwards. */
5923 if (!drwav_seek_to_first_pcm_frame(pWav)) {
5924 return DRWAV_FALSE;
5925 }
5926 offset = targetBytePos;
5927 }
5928
5929 while (offset > 0) {
5930 int offset32 = ((offset > INT_MAX) ? INT_MAX : (int)offset);
5931 if (!pWav->onSeek(pWav->pUserData, offset32, drwav_seek_origin_current)) {
5932 return DRWAV_FALSE;
5933 }
5934
5935 pWav->readCursorInPCMFrames += offset32 / bytesPerFrame;
5936 pWav->bytesRemaining -= offset32;
5937 offset -= offset32;
5938 }
5939 }
5940
5941 return DRWAV_TRUE;
5942}
5943
5944DRWAV_API drwav_result drwav_get_cursor_in_pcm_frames(drwav* pWav, drwav_uint64* pCursor)
5945{
5946 if (pCursor == NULL) {
5947 return DRWAV_INVALID_ARGS;
5948 }
5949
5950 *pCursor = 0; /* Safety. */
5951
5952 if (pWav == NULL) {
5953 return DRWAV_INVALID_ARGS;
5954 }
5955
5956 *pCursor = pWav->readCursorInPCMFrames;
5957
5958 return DRWAV_SUCCESS;
5959}
5960
5961DRWAV_API drwav_result drwav_get_length_in_pcm_frames(drwav* pWav, drwav_uint64* pLength)
5962{
5963 if (pLength == NULL) {
5964 return DRWAV_INVALID_ARGS;
5965 }
5966
5967 *pLength = 0; /* Safety. */
5968
5969 if (pWav == NULL) {
5970 return DRWAV_INVALID_ARGS;
5971 }
5972
5973 *pLength = pWav->totalPCMFrameCount;
5974
5975 return DRWAV_SUCCESS;
5976}
5977
5978
5979DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData)
5980{
5981 size_t bytesWritten;
5982
5983 if (pWav == NULL || bytesToWrite == 0 || pData == NULL) {
5984 return 0;
5985 }
5986
5987 bytesWritten = pWav->onWrite(pWav->pUserData, pData, bytesToWrite);
5988 pWav->dataChunkDataSize += bytesWritten;
5989
5990 return bytesWritten;
5991}
5992
5993DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData)
5994{
5995 drwav_uint64 bytesToWrite;
5996 drwav_uint64 bytesWritten;
5997 const drwav_uint8* pRunningData;
5998
5999 if (pWav == NULL || framesToWrite == 0 || pData == NULL) {
6000 return 0;
6001 }
6002
6003 bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8);
6004 if (bytesToWrite > DRWAV_SIZE_MAX) {
6005 return 0;
6006 }
6007
6008 bytesWritten = 0;
6009 pRunningData = (const drwav_uint8*)pData;
6010
6011 while (bytesToWrite > 0) {
6012 size_t bytesJustWritten;
6013 drwav_uint64 bytesToWriteThisIteration;
6014
6015 bytesToWriteThisIteration = bytesToWrite;
6016 DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX); /* <-- This is checked above. */
6017
6018 bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, pRunningData);
6019 if (bytesJustWritten == 0) {
6020 break;
6021 }
6022
6023 bytesToWrite -= bytesJustWritten;
6024 bytesWritten += bytesJustWritten;
6025 pRunningData += bytesJustWritten;
6026 }
6027
6028 return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels;
6029}
6030
6031DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData)
6032{
6033 drwav_uint64 bytesToWrite;
6034 drwav_uint64 bytesWritten;
6035 drwav_uint32 bytesPerSample;
6036 const drwav_uint8* pRunningData;
6037
6038 if (pWav == NULL || framesToWrite == 0 || pData == NULL) {
6039 return 0;
6040 }
6041
6042 bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8);
6043 if (bytesToWrite > DRWAV_SIZE_MAX) {
6044 return 0;
6045 }
6046
6047 bytesWritten = 0;
6048 pRunningData = (const drwav_uint8*)pData;
6049
6050 bytesPerSample = drwav_get_bytes_per_pcm_frame(pWav) / pWav->channels;
6051 if (bytesPerSample == 0) {
6052 return 0; /* Cannot determine bytes per sample, or bytes per sample is less than one byte. */
6053 }
6054
6055 while (bytesToWrite > 0) {
6056 drwav_uint8 temp[4096];
6057 drwav_uint32 sampleCount;
6058 size_t bytesJustWritten;
6059 drwav_uint64 bytesToWriteThisIteration;
6060
6061 bytesToWriteThisIteration = bytesToWrite;
6062 DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX); /* <-- This is checked above. */
6063
6064 /*
6065 WAV files are always little-endian. We need to byte swap on big-endian architectures. Since our input buffer is read-only we need
6066 to use an intermediary buffer for the conversion.
6067 */
6068 sampleCount = sizeof(temp)/bytesPerSample;
6069
6070 if (bytesToWriteThisIteration > ((drwav_uint64)sampleCount)*bytesPerSample) {
6071 bytesToWriteThisIteration = ((drwav_uint64)sampleCount)*bytesPerSample;
6072 }
6073
6074 DRWAV_COPY_MEMORY(temp, pRunningData, (size_t)bytesToWriteThisIteration);
6075 drwav__bswap_samples(temp, sampleCount, bytesPerSample);
6076
6077 bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, temp);
6078 if (bytesJustWritten == 0) {
6079 break;
6080 }
6081
6082 bytesToWrite -= bytesJustWritten;
6083 bytesWritten += bytesJustWritten;
6084 pRunningData += bytesJustWritten;
6085 }
6086
6087 return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels;
6088}
6089
6090DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData)
6091{
6092 if (drwav__is_little_endian()) {
6093 return drwav_write_pcm_frames_le(pWav, framesToWrite, pData);
6094 } else {
6095 return drwav_write_pcm_frames_be(pWav, framesToWrite, pData);
6096 }
6097}
6098
6099
6100DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
6101{
6102 drwav_uint64 totalFramesRead = 0;
6103
6104 DRWAV_ASSERT(pWav != NULL);
6105 DRWAV_ASSERT(framesToRead > 0);
6106
6107 /* TODO: Lots of room for optimization here. */
6108
6109 while (pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) {
6110 DRWAV_ASSERT(framesToRead > 0); /* This loop iteration will never get hit with framesToRead == 0 because it's asserted at the top, and we check for 0 inside the loop just below. */
6111
6112 /* If there are no cached frames we need to load a new block. */
6113 if (pWav->msadpcm.cachedFrameCount == 0 && pWav->msadpcm.bytesRemainingInBlock == 0) {
6114 if (pWav->channels == 1) {
6115 /* Mono. */
6116 drwav_uint8 header[7];
6117 if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
6118 return totalFramesRead;
6119 }
6120 pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
6121
6122 pWav->msadpcm.predictor[0] = header[0];
6123 pWav->msadpcm.delta[0] = drwav_bytes_to_s16(header + 1);
6124 pWav->msadpcm.prevFrames[0][1] = (drwav_int32)drwav_bytes_to_s16(header + 3);
6125 pWav->msadpcm.prevFrames[0][0] = (drwav_int32)drwav_bytes_to_s16(header + 5);
6126 pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][0];
6127 pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[0][1];
6128 pWav->msadpcm.cachedFrameCount = 2;
6129 } else {
6130 /* Stereo. */
6131 drwav_uint8 header[14];
6132 if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
6133 return totalFramesRead;
6134 }
6135 pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
6136
6137 pWav->msadpcm.predictor[0] = header[0];
6138 pWav->msadpcm.predictor[1] = header[1];
6139 pWav->msadpcm.delta[0] = drwav_bytes_to_s16(header + 2);
6140 pWav->msadpcm.delta[1] = drwav_bytes_to_s16(header + 4);
6141 pWav->msadpcm.prevFrames[0][1] = (drwav_int32)drwav_bytes_to_s16(header + 6);
6142 pWav->msadpcm.prevFrames[1][1] = (drwav_int32)drwav_bytes_to_s16(header + 8);
6143 pWav->msadpcm.prevFrames[0][0] = (drwav_int32)drwav_bytes_to_s16(header + 10);
6144 pWav->msadpcm.prevFrames[1][0] = (drwav_int32)drwav_bytes_to_s16(header + 12);
6145
6146 pWav->msadpcm.cachedFrames[0] = pWav->msadpcm.prevFrames[0][0];
6147 pWav->msadpcm.cachedFrames[1] = pWav->msadpcm.prevFrames[1][0];
6148 pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][1];
6149 pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[1][1];
6150 pWav->msadpcm.cachedFrameCount = 2;
6151 }
6152 }
6153
6154 /* Output anything that's cached. */
6155 while (framesToRead > 0 && pWav->msadpcm.cachedFrameCount > 0 && pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) {
6156 if (pBufferOut != NULL) {
6157 drwav_uint32 iSample = 0;
6158 for (iSample = 0; iSample < pWav->channels; iSample += 1) {
6159 pBufferOut[iSample] = (drwav_int16)pWav->msadpcm.cachedFrames[(drwav_countof(pWav->msadpcm.cachedFrames) - (pWav->msadpcm.cachedFrameCount*pWav->channels)) + iSample];
6160 }
6161
6162 pBufferOut += pWav->channels;
6163 }
6164
6165 framesToRead -= 1;
6166 totalFramesRead += 1;
6167 pWav->readCursorInPCMFrames += 1;
6168 pWav->msadpcm.cachedFrameCount -= 1;
6169 }
6170
6171 if (framesToRead == 0) {
6172 break;
6173 }
6174
6175
6176 /*
6177 If there's nothing left in the cache, just go ahead and load more. If there's nothing left to load in the current block we just continue to the next
6178 loop iteration which will trigger the loading of a new block.
6179 */
6180 if (pWav->msadpcm.cachedFrameCount == 0) {
6181 if (pWav->msadpcm.bytesRemainingInBlock == 0) {
6182 continue;
6183 } else {
6184 static drwav_int32 adaptationTable[] = {
6185 230, 230, 230, 230, 307, 409, 512, 614,
6186 768, 614, 512, 409, 307, 230, 230, 230
6187 };
6188 static drwav_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 };
6189 static drwav_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 };
6190
6191 drwav_uint8 nibbles;
6192 drwav_int32 nibble0;
6193 drwav_int32 nibble1;
6194
6195 if (pWav->onRead(pWav->pUserData, &nibbles, 1) != 1) {
6196 return totalFramesRead;
6197 }
6198 pWav->msadpcm.bytesRemainingInBlock -= 1;
6199
6200 /* TODO: Optimize away these if statements. */
6201 nibble0 = ((nibbles & 0xF0) >> 4); if ((nibbles & 0x80)) { nibble0 |= 0xFFFFFFF0UL; }
6202 nibble1 = ((nibbles & 0x0F) >> 0); if ((nibbles & 0x08)) { nibble1 |= 0xFFFFFFF0UL; }
6203
6204 if (pWav->channels == 1) {
6205 /* Mono. */
6206 drwav_int32 newSample0;
6207 drwav_int32 newSample1;
6208
6209 newSample0 = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
6210 newSample0 += nibble0 * pWav->msadpcm.delta[0];
6211 newSample0 = drwav_clamp(newSample0, -32768, 32767);
6212
6213 pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8;
6214 if (pWav->msadpcm.delta[0] < 16) {
6215 pWav->msadpcm.delta[0] = 16;
6216 }
6217
6218 pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
6219 pWav->msadpcm.prevFrames[0][1] = newSample0;
6220
6221
6222 newSample1 = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
6223 newSample1 += nibble1 * pWav->msadpcm.delta[0];
6224 newSample1 = drwav_clamp(newSample1, -32768, 32767);
6225
6226 pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[0]) >> 8;
6227 if (pWav->msadpcm.delta[0] < 16) {
6228 pWav->msadpcm.delta[0] = 16;
6229 }
6230
6231 pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
6232 pWav->msadpcm.prevFrames[0][1] = newSample1;
6233
6234
6235 pWav->msadpcm.cachedFrames[2] = newSample0;
6236 pWav->msadpcm.cachedFrames[3] = newSample1;
6237 pWav->msadpcm.cachedFrameCount = 2;
6238 } else {
6239 /* Stereo. */
6240 drwav_int32 newSample0;
6241 drwav_int32 newSample1;
6242
6243 /* Left. */
6244 newSample0 = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
6245 newSample0 += nibble0 * pWav->msadpcm.delta[0];
6246 newSample0 = drwav_clamp(newSample0, -32768, 32767);
6247
6248 pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8;
6249 if (pWav->msadpcm.delta[0] < 16) {
6250 pWav->msadpcm.delta[0] = 16;
6251 }
6252
6253 pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1];
6254 pWav->msadpcm.prevFrames[0][1] = newSample0;
6255
6256
6257 /* Right. */
6258 newSample1 = ((pWav->msadpcm.prevFrames[1][1] * coeff1Table[pWav->msadpcm.predictor[1]]) + (pWav->msadpcm.prevFrames[1][0] * coeff2Table[pWav->msadpcm.predictor[1]])) >> 8;
6259 newSample1 += nibble1 * pWav->msadpcm.delta[1];
6260 newSample1 = drwav_clamp(newSample1, -32768, 32767);
6261
6262 pWav->msadpcm.delta[1] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[1]) >> 8;
6263 if (pWav->msadpcm.delta[1] < 16) {
6264 pWav->msadpcm.delta[1] = 16;
6265 }
6266
6267 pWav->msadpcm.prevFrames[1][0] = pWav->msadpcm.prevFrames[1][1];
6268 pWav->msadpcm.prevFrames[1][1] = newSample1;
6269
6270 pWav->msadpcm.cachedFrames[2] = newSample0;
6271 pWav->msadpcm.cachedFrames[3] = newSample1;
6272 pWav->msadpcm.cachedFrameCount = 1;
6273 }
6274 }
6275 }
6276 }
6277
6278 return totalFramesRead;
6279}
6280
6281
6282DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
6283{
6284 drwav_uint64 totalFramesRead = 0;
6285 drwav_uint32 iChannel;
6286
6287 static drwav_int32 indexTable[16] = {
6288 -1, -1, -1, -1, 2, 4, 6, 8,
6289 -1, -1, -1, -1, 2, 4, 6, 8
6290 };
6291
6292 static drwav_int32 stepTable[89] = {
6293 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
6294 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
6295 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
6296 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
6297 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
6298 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
6299 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
6300 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
6301 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
6302 };
6303
6304 DRWAV_ASSERT(pWav != NULL);
6305 DRWAV_ASSERT(framesToRead > 0);
6306
6307 /* TODO: Lots of room for optimization here. */
6308
6309 while (pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) {
6310 DRWAV_ASSERT(framesToRead > 0); /* This loop iteration will never get hit with framesToRead == 0 because it's asserted at the top, and we check for 0 inside the loop just below. */
6311
6312 /* If there are no cached samples we need to load a new block. */
6313 if (pWav->ima.cachedFrameCount == 0 && pWav->ima.bytesRemainingInBlock == 0) {
6314 if (pWav->channels == 1) {
6315 /* Mono. */
6316 drwav_uint8 header[4];
6317 if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
6318 return totalFramesRead;
6319 }
6320 pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
6321
6322 if (header[2] >= drwav_countof(stepTable)) {
6323 pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, drwav_seek_origin_current);
6324 pWav->ima.bytesRemainingInBlock = 0;
6325 return totalFramesRead; /* Invalid data. */
6326 }
6327
6328 pWav->ima.predictor[0] = (drwav_int16)drwav_bytes_to_u16(header + 0);
6329 pWav->ima.stepIndex[0] = drwav_clamp(header[2], 0, (drwav_int32)drwav_countof(stepTable)-1); /* Clamp not necessary because we checked above, but adding here to silence a static analysis warning. */
6330 pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[0];
6331 pWav->ima.cachedFrameCount = 1;
6332 } else {
6333 /* Stereo. */
6334 drwav_uint8 header[8];
6335 if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
6336 return totalFramesRead;
6337 }
6338 pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
6339
6340 if (header[2] >= drwav_countof(stepTable) || header[6] >= drwav_countof(stepTable)) {
6341 pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, drwav_seek_origin_current);
6342 pWav->ima.bytesRemainingInBlock = 0;
6343 return totalFramesRead; /* Invalid data. */
6344 }
6345
6346 pWav->ima.predictor[0] = drwav_bytes_to_s16(header + 0);
6347 pWav->ima.stepIndex[0] = drwav_clamp(header[2], 0, (drwav_int32)drwav_countof(stepTable)-1); /* Clamp not necessary because we checked above, but adding here to silence a static analysis warning. */
6348 pWav->ima.predictor[1] = drwav_bytes_to_s16(header + 4);
6349 pWav->ima.stepIndex[1] = drwav_clamp(header[6], 0, (drwav_int32)drwav_countof(stepTable)-1); /* Clamp not necessary because we checked above, but adding here to silence a static analysis warning. */
6350
6351 pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 2] = pWav->ima.predictor[0];
6352 pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[1];
6353 pWav->ima.cachedFrameCount = 1;
6354 }
6355 }
6356
6357 /* Output anything that's cached. */
6358 while (framesToRead > 0 && pWav->ima.cachedFrameCount > 0 && pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) {
6359 if (pBufferOut != NULL) {
6360 drwav_uint32 iSample;
6361 for (iSample = 0; iSample < pWav->channels; iSample += 1) {
6362 pBufferOut[iSample] = (drwav_int16)pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + iSample];
6363 }
6364 pBufferOut += pWav->channels;
6365 }
6366
6367 framesToRead -= 1;
6368 totalFramesRead += 1;
6369 pWav->readCursorInPCMFrames += 1;
6370 pWav->ima.cachedFrameCount -= 1;
6371 }
6372
6373 if (framesToRead == 0) {
6374 break;
6375 }
6376
6377 /*
6378 If there's nothing left in the cache, just go ahead and load more. If there's nothing left to load in the current block we just continue to the next
6379 loop iteration which will trigger the loading of a new block.
6380 */
6381 if (pWav->ima.cachedFrameCount == 0) {
6382 if (pWav->ima.bytesRemainingInBlock == 0) {
6383 continue;
6384 } else {
6385 /*
6386 From what I can tell with stereo streams, it looks like every 4 bytes (8 samples) is for one channel. So it goes 4 bytes for the
6387 left channel, 4 bytes for the right channel.
6388 */
6389 pWav->ima.cachedFrameCount = 8;
6390 for (iChannel = 0; iChannel < pWav->channels; ++iChannel) {
6391 drwav_uint32 iByte;
6392 drwav_uint8 nibbles[4];
6393 if (pWav->onRead(pWav->pUserData, &nibbles, 4) != 4) {
6394 pWav->ima.cachedFrameCount = 0;
6395 return totalFramesRead;
6396 }
6397 pWav->ima.bytesRemainingInBlock -= 4;
6398
6399 for (iByte = 0; iByte < 4; ++iByte) {
6400 drwav_uint8 nibble0 = ((nibbles[iByte] & 0x0F) >> 0);
6401 drwav_uint8 nibble1 = ((nibbles[iByte] & 0xF0) >> 4);
6402
6403 drwav_int32 step = stepTable[pWav->ima.stepIndex[iChannel]];
6404 drwav_int32 predictor = pWav->ima.predictor[iChannel];
6405
6406 drwav_int32 diff = step >> 3;
6407 if (nibble0 & 1) diff += step >> 2;
6408 if (nibble0 & 2) diff += step >> 1;
6409 if (nibble0 & 4) diff += step;
6410 if (nibble0 & 8) diff = -diff;
6411
6412 predictor = drwav_clamp(predictor + diff, -32768, 32767);
6413 pWav->ima.predictor[iChannel] = predictor;
6414 pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble0], 0, (drwav_int32)drwav_countof(stepTable)-1);
6415 pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + (iByte*2+0)*pWav->channels + iChannel] = predictor;
6416
6417
6418 step = stepTable[pWav->ima.stepIndex[iChannel]];
6419 predictor = pWav->ima.predictor[iChannel];
6420
6421 diff = step >> 3;
6422 if (nibble1 & 1) diff += step >> 2;
6423 if (nibble1 & 2) diff += step >> 1;
6424 if (nibble1 & 4) diff += step;
6425 if (nibble1 & 8) diff = -diff;
6426
6427 predictor = drwav_clamp(predictor + diff, -32768, 32767);
6428 pWav->ima.predictor[iChannel] = predictor;
6429 pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble1], 0, (drwav_int32)drwav_countof(stepTable)-1);
6430 pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + (iByte*2+1)*pWav->channels + iChannel] = predictor;
6431 }
6432 }
6433 }
6434 }
6435 }
6436
6437 return totalFramesRead;
6438}
6439
6440
6441#ifndef DR_WAV_NO_CONVERSION_API
6442static unsigned short g_drwavAlawTable[256] = {
6443 0xEA80, 0xEB80, 0xE880, 0xE980, 0xEE80, 0xEF80, 0xEC80, 0xED80, 0xE280, 0xE380, 0xE080, 0xE180, 0xE680, 0xE780, 0xE480, 0xE580,
6444 0xF540, 0xF5C0, 0xF440, 0xF4C0, 0xF740, 0xF7C0, 0xF640, 0xF6C0, 0xF140, 0xF1C0, 0xF040, 0xF0C0, 0xF340, 0xF3C0, 0xF240, 0xF2C0,
6445 0xAA00, 0xAE00, 0xA200, 0xA600, 0xBA00, 0xBE00, 0xB200, 0xB600, 0x8A00, 0x8E00, 0x8200, 0x8600, 0x9A00, 0x9E00, 0x9200, 0x9600,
6446 0xD500, 0xD700, 0xD100, 0xD300, 0xDD00, 0xDF00, 0xD900, 0xDB00, 0xC500, 0xC700, 0xC100, 0xC300, 0xCD00, 0xCF00, 0xC900, 0xCB00,
6447 0xFEA8, 0xFEB8, 0xFE88, 0xFE98, 0xFEE8, 0xFEF8, 0xFEC8, 0xFED8, 0xFE28, 0xFE38, 0xFE08, 0xFE18, 0xFE68, 0xFE78, 0xFE48, 0xFE58,
6448 0xFFA8, 0xFFB8, 0xFF88, 0xFF98, 0xFFE8, 0xFFF8, 0xFFC8, 0xFFD8, 0xFF28, 0xFF38, 0xFF08, 0xFF18, 0xFF68, 0xFF78, 0xFF48, 0xFF58,
6449 0xFAA0, 0xFAE0, 0xFA20, 0xFA60, 0xFBA0, 0xFBE0, 0xFB20, 0xFB60, 0xF8A0, 0xF8E0, 0xF820, 0xF860, 0xF9A0, 0xF9E0, 0xF920, 0xF960,
6450 0xFD50, 0xFD70, 0xFD10, 0xFD30, 0xFDD0, 0xFDF0, 0xFD90, 0xFDB0, 0xFC50, 0xFC70, 0xFC10, 0xFC30, 0xFCD0, 0xFCF0, 0xFC90, 0xFCB0,
6451 0x1580, 0x1480, 0x1780, 0x1680, 0x1180, 0x1080, 0x1380, 0x1280, 0x1D80, 0x1C80, 0x1F80, 0x1E80, 0x1980, 0x1880, 0x1B80, 0x1A80,
6452 0x0AC0, 0x0A40, 0x0BC0, 0x0B40, 0x08C0, 0x0840, 0x09C0, 0x0940, 0x0EC0, 0x0E40, 0x0FC0, 0x0F40, 0x0CC0, 0x0C40, 0x0DC0, 0x0D40,
6453 0x5600, 0x5200, 0x5E00, 0x5A00, 0x4600, 0x4200, 0x4E00, 0x4A00, 0x7600, 0x7200, 0x7E00, 0x7A00, 0x6600, 0x6200, 0x6E00, 0x6A00,
6454 0x2B00, 0x2900, 0x2F00, 0x2D00, 0x2300, 0x2100, 0x2700, 0x2500, 0x3B00, 0x3900, 0x3F00, 0x3D00, 0x3300, 0x3100, 0x3700, 0x3500,
6455 0x0158, 0x0148, 0x0178, 0x0168, 0x0118, 0x0108, 0x0138, 0x0128, 0x01D8, 0x01C8, 0x01F8, 0x01E8, 0x0198, 0x0188, 0x01B8, 0x01A8,
6456 0x0058, 0x0048, 0x0078, 0x0068, 0x0018, 0x0008, 0x0038, 0x0028, 0x00D8, 0x00C8, 0x00F8, 0x00E8, 0x0098, 0x0088, 0x00B8, 0x00A8,
6457 0x0560, 0x0520, 0x05E0, 0x05A0, 0x0460, 0x0420, 0x04E0, 0x04A0, 0x0760, 0x0720, 0x07E0, 0x07A0, 0x0660, 0x0620, 0x06E0, 0x06A0,
6458 0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350
6459};
6460
6461static unsigned short g_drwavMulawTable[256] = {
6462 0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84, 0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84,
6463 0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84, 0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84,
6464 0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804, 0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004,
6465 0xF0C4, 0xF144, 0xF1C4, 0xF244, 0xF2C4, 0xF344, 0xF3C4, 0xF444, 0xF4C4, 0xF544, 0xF5C4, 0xF644, 0xF6C4, 0xF744, 0xF7C4, 0xF844,
6466 0xF8A4, 0xF8E4, 0xF924, 0xF964, 0xF9A4, 0xF9E4, 0xFA24, 0xFA64, 0xFAA4, 0xFAE4, 0xFB24, 0xFB64, 0xFBA4, 0xFBE4, 0xFC24, 0xFC64,
6467 0xFC94, 0xFCB4, 0xFCD4, 0xFCF4, 0xFD14, 0xFD34, 0xFD54, 0xFD74, 0xFD94, 0xFDB4, 0xFDD4, 0xFDF4, 0xFE14, 0xFE34, 0xFE54, 0xFE74,
6468 0xFE8C, 0xFE9C, 0xFEAC, 0xFEBC, 0xFECC, 0xFEDC, 0xFEEC, 0xFEFC, 0xFF0C, 0xFF1C, 0xFF2C, 0xFF3C, 0xFF4C, 0xFF5C, 0xFF6C, 0xFF7C,
6469 0xFF88, 0xFF90, 0xFF98, 0xFFA0, 0xFFA8, 0xFFB0, 0xFFB8, 0xFFC0, 0xFFC8, 0xFFD0, 0xFFD8, 0xFFE0, 0xFFE8, 0xFFF0, 0xFFF8, 0x0000,
6470 0x7D7C, 0x797C, 0x757C, 0x717C, 0x6D7C, 0x697C, 0x657C, 0x617C, 0x5D7C, 0x597C, 0x557C, 0x517C, 0x4D7C, 0x497C, 0x457C, 0x417C,
6471 0x3E7C, 0x3C7C, 0x3A7C, 0x387C, 0x367C, 0x347C, 0x327C, 0x307C, 0x2E7C, 0x2C7C, 0x2A7C, 0x287C, 0x267C, 0x247C, 0x227C, 0x207C,
6472 0x1EFC, 0x1DFC, 0x1CFC, 0x1BFC, 0x1AFC, 0x19FC, 0x18FC, 0x17FC, 0x16FC, 0x15FC, 0x14FC, 0x13FC, 0x12FC, 0x11FC, 0x10FC, 0x0FFC,
6473 0x0F3C, 0x0EBC, 0x0E3C, 0x0DBC, 0x0D3C, 0x0CBC, 0x0C3C, 0x0BBC, 0x0B3C, 0x0ABC, 0x0A3C, 0x09BC, 0x093C, 0x08BC, 0x083C, 0x07BC,
6474 0x075C, 0x071C, 0x06DC, 0x069C, 0x065C, 0x061C, 0x05DC, 0x059C, 0x055C, 0x051C, 0x04DC, 0x049C, 0x045C, 0x041C, 0x03DC, 0x039C,
6475 0x036C, 0x034C, 0x032C, 0x030C, 0x02EC, 0x02CC, 0x02AC, 0x028C, 0x026C, 0x024C, 0x022C, 0x020C, 0x01EC, 0x01CC, 0x01AC, 0x018C,
6476 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, 0x00F4, 0x00E4, 0x00D4, 0x00C4, 0x00B4, 0x00A4, 0x0094, 0x0084,
6477 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000
6478};
6479
6480static DRWAV_INLINE drwav_int16 drwav__alaw_to_s16(drwav_uint8 sampleIn)
6481{
6482 return (short)g_drwavAlawTable[sampleIn];
6483}
6484
6485static DRWAV_INLINE drwav_int16 drwav__mulaw_to_s16(drwav_uint8 sampleIn)
6486{
6487 return (short)g_drwavMulawTable[sampleIn];
6488}
6489
6490
6491
6492DRWAV_PRIVATE void drwav__pcm_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
6493{
6494 size_t i;
6495
6496 /* Special case for 8-bit sample data because it's treated as unsigned. */
6497 if (bytesPerSample == 1) {
6498 drwav_u8_to_s16(pOut, pIn, totalSampleCount);
6499 return;
6500 }
6501
6502
6503 /* Slightly more optimal implementation for common formats. */
6504 if (bytesPerSample == 2) {
6505 for (i = 0; i < totalSampleCount; ++i) {
6506 *pOut++ = ((const drwav_int16*)pIn)[i];
6507 }
6508 return;
6509 }
6510 if (bytesPerSample == 3) {
6511 drwav_s24_to_s16(pOut, pIn, totalSampleCount);
6512 return;
6513 }
6514 if (bytesPerSample == 4) {
6515 drwav_s32_to_s16(pOut, (const drwav_int32*)pIn, totalSampleCount);
6516 return;
6517 }
6518
6519
6520 /* Anything more than 64 bits per sample is not supported. */
6521 if (bytesPerSample > 8) {
6522 DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
6523 return;
6524 }
6525
6526
6527 /* Generic, slow converter. */
6528 for (i = 0; i < totalSampleCount; ++i) {
6529 drwav_uint64 sample = 0;
6530 unsigned int shift = (8 - bytesPerSample) * 8;
6531
6532 unsigned int j;
6533 for (j = 0; j < bytesPerSample; j += 1) {
6534 DRWAV_ASSERT(j < 8);
6535 sample |= (drwav_uint64)(pIn[j]) << shift;
6536 shift += 8;
6537 }
6538
6539 pIn += j;
6540 *pOut++ = (drwav_int16)((drwav_int64)sample >> 48);
6541 }
6542}
6543
6544DRWAV_PRIVATE void drwav__ieee_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
6545{
6546 if (bytesPerSample == 4) {
6547 drwav_f32_to_s16(pOut, (const float*)pIn, totalSampleCount);
6548 return;
6549 } else if (bytesPerSample == 8) {
6550 drwav_f64_to_s16(pOut, (const double*)pIn, totalSampleCount);
6551 return;
6552 } else {
6553 /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */
6554 DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
6555 return;
6556 }
6557}
6558
6559DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
6560{
6561 drwav_uint64 totalFramesRead;
6562 drwav_uint8 sampleData[4096] = {0};
6563 drwav_uint32 bytesPerFrame;
6564 drwav_uint32 bytesPerSample;
6565 drwav_uint64 samplesRead;
6566
6567 /* Fast path. */
6568 if ((pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 16) || pBufferOut == NULL) {
6569 return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut);
6570 }
6571
6572 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
6573 if (bytesPerFrame == 0) {
6574 return 0;
6575 }
6576
6577 bytesPerSample = bytesPerFrame / pWav->channels;
6578 if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
6579 return 0; /* Only byte-aligned formats are supported. */
6580 }
6581
6582 totalFramesRead = 0;
6583
6584 while (framesToRead > 0) {
6585 drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
6586 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
6587 if (framesRead == 0) {
6588 break;
6589 }
6590
6591 DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
6592
6593 /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */
6594 samplesRead = framesRead * pWav->channels;
6595 if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
6596 DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */
6597 break;
6598 }
6599
6600 drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample);
6601
6602 pBufferOut += samplesRead;
6603 framesToRead -= framesRead;
6604 totalFramesRead += framesRead;
6605 }
6606
6607 return totalFramesRead;
6608}
6609
6610DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
6611{
6612 drwav_uint64 totalFramesRead;
6613 drwav_uint8 sampleData[4096] = {0};
6614 drwav_uint32 bytesPerFrame;
6615 drwav_uint32 bytesPerSample;
6616 drwav_uint64 samplesRead;
6617
6618 if (pBufferOut == NULL) {
6619 return drwav_read_pcm_frames(pWav, framesToRead, NULL);
6620 }
6621
6622 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
6623 if (bytesPerFrame == 0) {
6624 return 0;
6625 }
6626
6627 bytesPerSample = bytesPerFrame / pWav->channels;
6628 if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
6629 return 0; /* Only byte-aligned formats are supported. */
6630 }
6631
6632 totalFramesRead = 0;
6633
6634 while (framesToRead > 0) {
6635 drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
6636 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
6637 if (framesRead == 0) {
6638 break;
6639 }
6640
6641 DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
6642
6643 /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */
6644 samplesRead = framesRead * pWav->channels;
6645 if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
6646 DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */
6647 break;
6648 }
6649
6650 drwav__ieee_to_s16(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample); /* Safe cast. */
6651
6652 pBufferOut += samplesRead;
6653 framesToRead -= framesRead;
6654 totalFramesRead += framesRead;
6655 }
6656
6657 return totalFramesRead;
6658}
6659
6660DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
6661{
6662 drwav_uint64 totalFramesRead;
6663 drwav_uint8 sampleData[4096] = {0};
6664 drwav_uint32 bytesPerFrame;
6665 drwav_uint32 bytesPerSample;
6666 drwav_uint64 samplesRead;
6667
6668 if (pBufferOut == NULL) {
6669 return drwav_read_pcm_frames(pWav, framesToRead, NULL);
6670 }
6671
6672 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
6673 if (bytesPerFrame == 0) {
6674 return 0;
6675 }
6676
6677 bytesPerSample = bytesPerFrame / pWav->channels;
6678 if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
6679 return 0; /* Only byte-aligned formats are supported. */
6680 }
6681
6682 totalFramesRead = 0;
6683
6684 while (framesToRead > 0) {
6685 drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
6686 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
6687 if (framesRead == 0) {
6688 break;
6689 }
6690
6691 DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
6692
6693 /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */
6694 samplesRead = framesRead * pWav->channels;
6695 if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
6696 DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */
6697 break;
6698 }
6699
6700 drwav_alaw_to_s16(pBufferOut, sampleData, (size_t)samplesRead);
6701
6702 /*
6703 For some reason libsndfile seems to be returning samples of the opposite sign for a-law, but only
6704 with AIFF files. For WAV files it seems to be the same as dr_wav. This is resulting in dr_wav's
6705 automated tests failing. I'm not sure which is correct, but will assume dr_wav. If we're enforcing
6706 libsndfile compatibility we'll swap the signs here.
6707 */
6708 #ifdef DR_WAV_LIBSNDFILE_COMPAT
6709 {
6710 if (pWav->container == drwav_container_aiff) {
6711 drwav_uint64 iSample;
6712 for (iSample = 0; iSample < samplesRead; iSample += 1) {
6713 pBufferOut[iSample] = -pBufferOut[iSample];
6714 }
6715 }
6716 }
6717 #endif
6718
6719 pBufferOut += samplesRead;
6720 framesToRead -= framesRead;
6721 totalFramesRead += framesRead;
6722 }
6723
6724 return totalFramesRead;
6725}
6726
6727DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s16__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
6728{
6729 drwav_uint64 totalFramesRead;
6730 drwav_uint8 sampleData[4096] = {0};
6731 drwav_uint32 bytesPerFrame;
6732 drwav_uint32 bytesPerSample;
6733 drwav_uint64 samplesRead;
6734
6735 if (pBufferOut == NULL) {
6736 return drwav_read_pcm_frames(pWav, framesToRead, NULL);
6737 }
6738
6739 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
6740 if (bytesPerFrame == 0) {
6741 return 0;
6742 }
6743
6744 bytesPerSample = bytesPerFrame / pWav->channels;
6745 if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
6746 return 0; /* Only byte-aligned formats are supported. */
6747 }
6748
6749 totalFramesRead = 0;
6750
6751 while (framesToRead > 0) {
6752 drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
6753 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
6754 if (framesRead == 0) {
6755 break;
6756 }
6757
6758 DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
6759
6760 /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */
6761 samplesRead = framesRead * pWav->channels;
6762 if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
6763 DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */
6764 break;
6765 }
6766
6767 drwav_mulaw_to_s16(pBufferOut, sampleData, (size_t)samplesRead);
6768
6769 /*
6770 Just like with alaw, for some reason the signs between libsndfile and dr_wav are opposite. We just need to
6771 swap the sign if we're compiling with libsndfile compatiblity so our automated tests don't fail.
6772 */
6773 #ifdef DR_WAV_LIBSNDFILE_COMPAT
6774 {
6775 if (pWav->container == drwav_container_aiff) {
6776 drwav_uint64 iSample;
6777 for (iSample = 0; iSample < samplesRead; iSample += 1) {
6778 pBufferOut[iSample] = -pBufferOut[iSample];
6779 }
6780 }
6781 }
6782 #endif
6783
6784 pBufferOut += samplesRead;
6785 framesToRead -= framesRead;
6786 totalFramesRead += framesRead;
6787 }
6788
6789 return totalFramesRead;
6790}
6791
6792DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
6793{
6794 if (pWav == NULL || framesToRead == 0) {
6795 return 0;
6796 }
6797
6798 if (pBufferOut == NULL) {
6799 return drwav_read_pcm_frames(pWav, framesToRead, NULL);
6800 }
6801
6802 /* Don't try to read more samples than can potentially fit in the output buffer. */
6803 if (framesToRead * pWav->channels * sizeof(drwav_int16) > DRWAV_SIZE_MAX) {
6804 framesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int16) / pWav->channels;
6805 }
6806
6807 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
6808 return drwav_read_pcm_frames_s16__pcm(pWav, framesToRead, pBufferOut);
6809 }
6810
6811 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
6812 return drwav_read_pcm_frames_s16__ieee(pWav, framesToRead, pBufferOut);
6813 }
6814
6815 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
6816 return drwav_read_pcm_frames_s16__alaw(pWav, framesToRead, pBufferOut);
6817 }
6818
6819 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
6820 return drwav_read_pcm_frames_s16__mulaw(pWav, framesToRead, pBufferOut);
6821 }
6822
6823 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
6824 return drwav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, pBufferOut);
6825 }
6826
6827 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
6828 return drwav_read_pcm_frames_s16__ima(pWav, framesToRead, pBufferOut);
6829 }
6830
6831 return 0;
6832}
6833
6834DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
6835{
6836 drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToRead, pBufferOut);
6837 if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) {
6838 drwav__bswap_samples_s16(pBufferOut, framesRead*pWav->channels);
6839 }
6840
6841 return framesRead;
6842}
6843
6844DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut)
6845{
6846 drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToRead, pBufferOut);
6847 if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) {
6848 drwav__bswap_samples_s16(pBufferOut, framesRead*pWav->channels);
6849 }
6850
6851 return framesRead;
6852}
6853
6854
6855DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
6856{
6857 int r;
6858 size_t i;
6859 for (i = 0; i < sampleCount; ++i) {
6860 int x = pIn[i];
6861 r = x << 8;
6862 r = r - 32768;
6863 pOut[i] = (short)r;
6864 }
6865}
6866
6867DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
6868{
6869 int r;
6870 size_t i;
6871 for (i = 0; i < sampleCount; ++i) {
6872 int x = ((int)(((unsigned int)(((const drwav_uint8*)pIn)[i*3+0]) << 8) | ((unsigned int)(((const drwav_uint8*)pIn)[i*3+1]) << 16) | ((unsigned int)(((const drwav_uint8*)pIn)[i*3+2])) << 24)) >> 8;
6873 r = x >> 8;
6874 pOut[i] = (short)r;
6875 }
6876}
6877
6878DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount)
6879{
6880 int r;
6881 size_t i;
6882 for (i = 0; i < sampleCount; ++i) {
6883 int x = pIn[i];
6884 r = x >> 16;
6885 pOut[i] = (short)r;
6886 }
6887}
6888
6889DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount)
6890{
6891 int r;
6892 size_t i;
6893 for (i = 0; i < sampleCount; ++i) {
6894 float x = pIn[i];
6895 float c;
6896 c = ((x < -1) ? -1 : ((x > 1) ? 1 : x));
6897 c = c + 1;
6898 r = (int)(c * 32767.5f);
6899 r = r - 32768;
6900 pOut[i] = (short)r;
6901 }
6902}
6903
6904DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount)
6905{
6906 int r;
6907 size_t i;
6908 for (i = 0; i < sampleCount; ++i) {
6909 double x = pIn[i];
6910 double c;
6911 c = ((x < -1) ? -1 : ((x > 1) ? 1 : x));
6912 c = c + 1;
6913 r = (int)(c * 32767.5);
6914 r = r - 32768;
6915 pOut[i] = (short)r;
6916 }
6917}
6918
6919DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
6920{
6921 size_t i;
6922 for (i = 0; i < sampleCount; ++i) {
6923 pOut[i] = drwav__alaw_to_s16(pIn[i]);
6924 }
6925}
6926
6927DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
6928{
6929 size_t i;
6930 for (i = 0; i < sampleCount; ++i) {
6931 pOut[i] = drwav__mulaw_to_s16(pIn[i]);
6932 }
6933}
6934
6935
6936DRWAV_PRIVATE void drwav__pcm_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample)
6937{
6938 unsigned int i;
6939
6940 /* Special case for 8-bit sample data because it's treated as unsigned. */
6941 if (bytesPerSample == 1) {
6942 drwav_u8_to_f32(pOut, pIn, sampleCount);
6943 return;
6944 }
6945
6946 /* Slightly more optimal implementation for common formats. */
6947 if (bytesPerSample == 2) {
6948 drwav_s16_to_f32(pOut, (const drwav_int16*)pIn, sampleCount);
6949 return;
6950 }
6951 if (bytesPerSample == 3) {
6952 drwav_s24_to_f32(pOut, pIn, sampleCount);
6953 return;
6954 }
6955 if (bytesPerSample == 4) {
6956 drwav_s32_to_f32(pOut, (const drwav_int32*)pIn, sampleCount);
6957 return;
6958 }
6959
6960
6961 /* Anything more than 64 bits per sample is not supported. */
6962 if (bytesPerSample > 8) {
6963 DRWAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut));
6964 return;
6965 }
6966
6967
6968 /* Generic, slow converter. */
6969 for (i = 0; i < sampleCount; ++i) {
6970 drwav_uint64 sample = 0;
6971 unsigned int shift = (8 - bytesPerSample) * 8;
6972
6973 unsigned int j;
6974 for (j = 0; j < bytesPerSample; j += 1) {
6975 DRWAV_ASSERT(j < 8);
6976 sample |= (drwav_uint64)(pIn[j]) << shift;
6977 shift += 8;
6978 }
6979
6980 pIn += j;
6981 *pOut++ = (float)((drwav_int64)sample / 9223372036854775807.0);
6982 }
6983}
6984
6985DRWAV_PRIVATE void drwav__ieee_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample)
6986{
6987 if (bytesPerSample == 4) {
6988 unsigned int i;
6989 for (i = 0; i < sampleCount; ++i) {
6990 *pOut++ = ((const float*)pIn)[i];
6991 }
6992 return;
6993 } else if (bytesPerSample == 8) {
6994 drwav_f64_to_f32(pOut, (const double*)pIn, sampleCount);
6995 return;
6996 } else {
6997 /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */
6998 DRWAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut));
6999 return;
7000 }
7001}
7002
7003
7004DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__pcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
7005{
7006 drwav_uint64 totalFramesRead;
7007 drwav_uint8 sampleData[4096] = {0};
7008 drwav_uint32 bytesPerFrame;
7009 drwav_uint32 bytesPerSample;
7010 drwav_uint64 samplesRead;
7011
7012 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
7013 if (bytesPerFrame == 0) {
7014 return 0;
7015 }
7016
7017 bytesPerSample = bytesPerFrame / pWav->channels;
7018 if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
7019 return 0; /* Only byte-aligned formats are supported. */
7020 }
7021
7022 totalFramesRead = 0;
7023
7024 while (framesToRead > 0) {
7025 drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
7026 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
7027 if (framesRead == 0) {
7028 break;
7029 }
7030
7031 DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
7032
7033 /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */
7034 samplesRead = framesRead * pWav->channels;
7035 if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
7036 DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */
7037 break;
7038 }
7039
7040 drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample);
7041
7042 pBufferOut += samplesRead;
7043 framesToRead -= framesRead;
7044 totalFramesRead += framesRead;
7045 }
7046
7047 return totalFramesRead;
7048}
7049
7050DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__msadpcm_ima(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
7051{
7052 /*
7053 We're just going to borrow the implementation from the drwav_read_s16() since ADPCM is a little bit more complicated than other formats and I don't
7054 want to duplicate that code.
7055 */
7056 drwav_uint64 totalFramesRead;
7057 drwav_int16 samples16[2048];
7058
7059 totalFramesRead = 0;
7060
7061 while (framesToRead > 0) {
7062 drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels);
7063 drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToReadThisIteration, samples16);
7064 if (framesRead == 0) {
7065 break;
7066 }
7067
7068 DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
7069
7070 drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */
7071
7072 pBufferOut += framesRead*pWav->channels;
7073 framesToRead -= framesRead;
7074 totalFramesRead += framesRead;
7075 }
7076
7077 return totalFramesRead;
7078}
7079
7080DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
7081{
7082 drwav_uint64 totalFramesRead;
7083 drwav_uint8 sampleData[4096] = {0};
7084 drwav_uint32 bytesPerFrame;
7085 drwav_uint32 bytesPerSample;
7086 drwav_uint64 samplesRead;
7087
7088 /* Fast path. */
7089 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT && pWav->bitsPerSample == 32) {
7090 return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut);
7091 }
7092
7093 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
7094 if (bytesPerFrame == 0) {
7095 return 0;
7096 }
7097
7098 bytesPerSample = bytesPerFrame / pWav->channels;
7099 if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
7100 return 0; /* Only byte-aligned formats are supported. */
7101 }
7102
7103 totalFramesRead = 0;
7104
7105 while (framesToRead > 0) {
7106 drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
7107 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
7108 if (framesRead == 0) {
7109 break;
7110 }
7111
7112 DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
7113
7114 /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */
7115 samplesRead = framesRead * pWav->channels;
7116 if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
7117 DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */
7118 break;
7119 }
7120
7121 drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample);
7122
7123 pBufferOut += samplesRead;
7124 framesToRead -= framesRead;
7125 totalFramesRead += framesRead;
7126 }
7127
7128 return totalFramesRead;
7129}
7130
7131DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__alaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
7132{
7133 drwav_uint64 totalFramesRead;
7134 drwav_uint8 sampleData[4096] = {0};
7135 drwav_uint32 bytesPerFrame;
7136 drwav_uint32 bytesPerSample;
7137 drwav_uint64 samplesRead;
7138
7139 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
7140 if (bytesPerFrame == 0) {
7141 return 0;
7142 }
7143
7144 bytesPerSample = bytesPerFrame / pWav->channels;
7145 if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
7146 return 0; /* Only byte-aligned formats are supported. */
7147 }
7148
7149 totalFramesRead = 0;
7150
7151 while (framesToRead > 0) {
7152 drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
7153 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
7154 if (framesRead == 0) {
7155 break;
7156 }
7157
7158 DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
7159
7160 /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */
7161 samplesRead = framesRead * pWav->channels;
7162 if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
7163 DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */
7164 break;
7165 }
7166
7167 drwav_alaw_to_f32(pBufferOut, sampleData, (size_t)samplesRead);
7168
7169 #ifdef DR_WAV_LIBSNDFILE_COMPAT
7170 {
7171 if (pWav->container == drwav_container_aiff) {
7172 drwav_uint64 iSample;
7173 for (iSample = 0; iSample < samplesRead; iSample += 1) {
7174 pBufferOut[iSample] = -pBufferOut[iSample];
7175 }
7176 }
7177 }
7178 #endif
7179
7180 pBufferOut += samplesRead;
7181 framesToRead -= framesRead;
7182 totalFramesRead += framesRead;
7183 }
7184
7185 return totalFramesRead;
7186}
7187
7188DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_f32__mulaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
7189{
7190 drwav_uint64 totalFramesRead;
7191 drwav_uint8 sampleData[4096] = {0};
7192 drwav_uint32 bytesPerFrame;
7193 drwav_uint32 bytesPerSample;
7194 drwav_uint64 samplesRead;
7195
7196 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
7197 if (bytesPerFrame == 0) {
7198 return 0;
7199 }
7200
7201 bytesPerSample = bytesPerFrame / pWav->channels;
7202 if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
7203 return 0; /* Only byte-aligned formats are supported. */
7204 }
7205
7206 totalFramesRead = 0;
7207
7208 while (framesToRead > 0) {
7209 drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
7210 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
7211 if (framesRead == 0) {
7212 break;
7213 }
7214
7215 DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
7216
7217 /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */
7218 samplesRead = framesRead * pWav->channels;
7219 if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
7220 DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */
7221 break;
7222 }
7223
7224 drwav_mulaw_to_f32(pBufferOut, sampleData, (size_t)samplesRead);
7225
7226 #ifdef DR_WAV_LIBSNDFILE_COMPAT
7227 {
7228 if (pWav->container == drwav_container_aiff) {
7229 drwav_uint64 iSample;
7230 for (iSample = 0; iSample < samplesRead; iSample += 1) {
7231 pBufferOut[iSample] = -pBufferOut[iSample];
7232 }
7233 }
7234 }
7235 #endif
7236
7237 pBufferOut += samplesRead;
7238 framesToRead -= framesRead;
7239 totalFramesRead += framesRead;
7240 }
7241
7242 return totalFramesRead;
7243}
7244
7245DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
7246{
7247 if (pWav == NULL || framesToRead == 0) {
7248 return 0;
7249 }
7250
7251 if (pBufferOut == NULL) {
7252 return drwav_read_pcm_frames(pWav, framesToRead, NULL);
7253 }
7254
7255 /* Don't try to read more samples than can potentially fit in the output buffer. */
7256 if (framesToRead * pWav->channels * sizeof(float) > DRWAV_SIZE_MAX) {
7257 framesToRead = DRWAV_SIZE_MAX / sizeof(float) / pWav->channels;
7258 }
7259
7260 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
7261 return drwav_read_pcm_frames_f32__pcm(pWav, framesToRead, pBufferOut);
7262 }
7263
7264 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
7265 return drwav_read_pcm_frames_f32__msadpcm_ima(pWav, framesToRead, pBufferOut);
7266 }
7267
7268 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
7269 return drwav_read_pcm_frames_f32__ieee(pWav, framesToRead, pBufferOut);
7270 }
7271
7272 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
7273 return drwav_read_pcm_frames_f32__alaw(pWav, framesToRead, pBufferOut);
7274 }
7275
7276 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
7277 return drwav_read_pcm_frames_f32__mulaw(pWav, framesToRead, pBufferOut);
7278 }
7279
7280 return 0;
7281}
7282
7283DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
7284{
7285 drwav_uint64 framesRead = drwav_read_pcm_frames_f32(pWav, framesToRead, pBufferOut);
7286 if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) {
7287 drwav__bswap_samples_f32(pBufferOut, framesRead*pWav->channels);
7288 }
7289
7290 return framesRead;
7291}
7292
7293DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut)
7294{
7295 drwav_uint64 framesRead = drwav_read_pcm_frames_f32(pWav, framesToRead, pBufferOut);
7296 if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) {
7297 drwav__bswap_samples_f32(pBufferOut, framesRead*pWav->channels);
7298 }
7299
7300 return framesRead;
7301}
7302
7303
7304DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
7305{
7306 size_t i;
7307
7308 if (pOut == NULL || pIn == NULL) {
7309 return;
7310 }
7311
7312#ifdef DR_WAV_LIBSNDFILE_COMPAT
7313 /*
7314 It appears libsndfile uses slightly different logic for the u8 -> f32 conversion to dr_wav, which in my opinion is incorrect. It appears
7315 libsndfile performs the conversion something like "f32 = (u8 / 256) * 2 - 1", however I think it should be "f32 = (u8 / 255) * 2 - 1" (note
7316 the divisor of 256 vs 255). I use libsndfile as a benchmark for testing, so I'm therefore leaving this block here just for my automated
7317 correctness testing. This is disabled by default.
7318 */
7319 for (i = 0; i < sampleCount; ++i) {
7320 *pOut++ = (pIn[i] / 256.0f) * 2 - 1;
7321 }
7322#else
7323 for (i = 0; i < sampleCount; ++i) {
7324 float x = pIn[i];
7325 x = x * 0.00784313725490196078f; /* 0..255 to 0..2 */
7326 x = x - 1; /* 0..2 to -1..1 */
7327
7328 *pOut++ = x;
7329 }
7330#endif
7331}
7332
7333DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount)
7334{
7335 size_t i;
7336
7337 if (pOut == NULL || pIn == NULL) {
7338 return;
7339 }
7340
7341 for (i = 0; i < sampleCount; ++i) {
7342 *pOut++ = pIn[i] * 0.000030517578125f;
7343 }
7344}
7345
7346DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
7347{
7348 size_t i;
7349
7350 if (pOut == NULL || pIn == NULL) {
7351 return;
7352 }
7353
7354 for (i = 0; i < sampleCount; ++i) {
7355 double x;
7356 drwav_uint32 a = ((drwav_uint32)(pIn[i*3+0]) << 8);
7357 drwav_uint32 b = ((drwav_uint32)(pIn[i*3+1]) << 16);
7358 drwav_uint32 c = ((drwav_uint32)(pIn[i*3+2]) << 24);
7359
7360 x = (double)((drwav_int32)(a | b | c) >> 8);
7361 *pOut++ = (float)(x * 0.00000011920928955078125);
7362 }
7363}
7364
7365DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount)
7366{
7367 size_t i;
7368 if (pOut == NULL || pIn == NULL) {
7369 return;
7370 }
7371
7372 for (i = 0; i < sampleCount; ++i) {
7373 *pOut++ = (float)(pIn[i] / 2147483648.0);
7374 }
7375}
7376
7377DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount)
7378{
7379 size_t i;
7380
7381 if (pOut == NULL || pIn == NULL) {
7382 return;
7383 }
7384
7385 for (i = 0; i < sampleCount; ++i) {
7386 *pOut++ = (float)pIn[i];
7387 }
7388}
7389
7390DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
7391{
7392 size_t i;
7393
7394 if (pOut == NULL || pIn == NULL) {
7395 return;
7396 }
7397
7398 for (i = 0; i < sampleCount; ++i) {
7399 *pOut++ = drwav__alaw_to_s16(pIn[i]) / 32768.0f;
7400 }
7401}
7402
7403DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
7404{
7405 size_t i;
7406
7407 if (pOut == NULL || pIn == NULL) {
7408 return;
7409 }
7410
7411 for (i = 0; i < sampleCount; ++i) {
7412 *pOut++ = drwav__mulaw_to_s16(pIn[i]) / 32768.0f;
7413 }
7414}
7415
7416
7417
7418DRWAV_PRIVATE void drwav__pcm_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
7419{
7420 unsigned int i;
7421
7422 /* Special case for 8-bit sample data because it's treated as unsigned. */
7423 if (bytesPerSample == 1) {
7424 drwav_u8_to_s32(pOut, pIn, totalSampleCount);
7425 return;
7426 }
7427
7428 /* Slightly more optimal implementation for common formats. */
7429 if (bytesPerSample == 2) {
7430 drwav_s16_to_s32(pOut, (const drwav_int16*)pIn, totalSampleCount);
7431 return;
7432 }
7433 if (bytesPerSample == 3) {
7434 drwav_s24_to_s32(pOut, pIn, totalSampleCount);
7435 return;
7436 }
7437 if (bytesPerSample == 4) {
7438 for (i = 0; i < totalSampleCount; ++i) {
7439 *pOut++ = ((const drwav_int32*)pIn)[i];
7440 }
7441 return;
7442 }
7443
7444
7445 /* Anything more than 64 bits per sample is not supported. */
7446 if (bytesPerSample > 8) {
7447 DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
7448 return;
7449 }
7450
7451
7452 /* Generic, slow converter. */
7453 for (i = 0; i < totalSampleCount; ++i) {
7454 drwav_uint64 sample = 0;
7455 unsigned int shift = (8 - bytesPerSample) * 8;
7456
7457 unsigned int j;
7458 for (j = 0; j < bytesPerSample; j += 1) {
7459 DRWAV_ASSERT(j < 8);
7460 sample |= (drwav_uint64)(pIn[j]) << shift;
7461 shift += 8;
7462 }
7463
7464 pIn += j;
7465 *pOut++ = (drwav_int32)((drwav_int64)sample >> 32);
7466 }
7467}
7468
7469DRWAV_PRIVATE void drwav__ieee_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample)
7470{
7471 if (bytesPerSample == 4) {
7472 drwav_f32_to_s32(pOut, (const float*)pIn, totalSampleCount);
7473 return;
7474 } else if (bytesPerSample == 8) {
7475 drwav_f64_to_s32(pOut, (const double*)pIn, totalSampleCount);
7476 return;
7477 } else {
7478 /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */
7479 DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut));
7480 return;
7481 }
7482}
7483
7484
7485DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
7486{
7487 drwav_uint64 totalFramesRead;
7488 drwav_uint8 sampleData[4096] = {0};
7489 drwav_uint32 bytesPerFrame;
7490 drwav_uint32 bytesPerSample;
7491 drwav_uint64 samplesRead;
7492
7493 /* Fast path. */
7494 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 32) {
7495 return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut);
7496 }
7497
7498 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
7499 if (bytesPerFrame == 0) {
7500 return 0;
7501 }
7502
7503 bytesPerSample = bytesPerFrame / pWav->channels;
7504 if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
7505 return 0; /* Only byte-aligned formats are supported. */
7506 }
7507
7508 totalFramesRead = 0;
7509
7510 while (framesToRead > 0) {
7511 drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
7512 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
7513 if (framesRead == 0) {
7514 break;
7515 }
7516
7517 DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
7518
7519 /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */
7520 samplesRead = framesRead * pWav->channels;
7521 if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
7522 DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */
7523 break;
7524 }
7525
7526 drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample);
7527
7528 pBufferOut += samplesRead;
7529 framesToRead -= framesRead;
7530 totalFramesRead += framesRead;
7531 }
7532
7533 return totalFramesRead;
7534}
7535
7536DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__msadpcm_ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
7537{
7538 /*
7539 We're just going to borrow the implementation from the drwav_read_s16() since ADPCM is a little bit more complicated than other formats and I don't
7540 want to duplicate that code.
7541 */
7542 drwav_uint64 totalFramesRead = 0;
7543 drwav_int16 samples16[2048];
7544
7545 while (framesToRead > 0) {
7546 drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels);
7547 drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToReadThisIteration, samples16);
7548 if (framesRead == 0) {
7549 break;
7550 }
7551
7552 DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
7553
7554 drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */
7555
7556 pBufferOut += framesRead*pWav->channels;
7557 framesToRead -= framesRead;
7558 totalFramesRead += framesRead;
7559 }
7560
7561 return totalFramesRead;
7562}
7563
7564DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
7565{
7566 drwav_uint64 totalFramesRead;
7567 drwav_uint8 sampleData[4096] = {0};
7568 drwav_uint32 bytesPerFrame;
7569 drwav_uint32 bytesPerSample;
7570 drwav_uint64 samplesRead;
7571
7572 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
7573 if (bytesPerFrame == 0) {
7574 return 0;
7575 }
7576
7577 bytesPerSample = bytesPerFrame / pWav->channels;
7578 if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
7579 return 0; /* Only byte-aligned formats are supported. */
7580 }
7581
7582 totalFramesRead = 0;
7583
7584 while (framesToRead > 0) {
7585 drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
7586 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
7587 if (framesRead == 0) {
7588 break;
7589 }
7590
7591 DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
7592
7593 /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */
7594 samplesRead = framesRead * pWav->channels;
7595 if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
7596 DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */
7597 break;
7598 }
7599
7600 drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)samplesRead, bytesPerSample);
7601
7602 pBufferOut += samplesRead;
7603 framesToRead -= framesRead;
7604 totalFramesRead += framesRead;
7605 }
7606
7607 return totalFramesRead;
7608}
7609
7610DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
7611{
7612 drwav_uint64 totalFramesRead;
7613 drwav_uint8 sampleData[4096] = {0};
7614 drwav_uint32 bytesPerFrame;
7615 drwav_uint32 bytesPerSample;
7616 drwav_uint64 samplesRead;
7617
7618 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
7619 if (bytesPerFrame == 0) {
7620 return 0;
7621 }
7622
7623 bytesPerSample = bytesPerFrame / pWav->channels;
7624 if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
7625 return 0; /* Only byte-aligned formats are supported. */
7626 }
7627
7628 totalFramesRead = 0;
7629
7630 while (framesToRead > 0) {
7631 drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
7632 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
7633 if (framesRead == 0) {
7634 break;
7635 }
7636
7637 DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
7638
7639 /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */
7640 samplesRead = framesRead * pWav->channels;
7641 if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
7642 DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */
7643 break;
7644 }
7645
7646 drwav_alaw_to_s32(pBufferOut, sampleData, (size_t)samplesRead);
7647
7648 #ifdef DR_WAV_LIBSNDFILE_COMPAT
7649 {
7650 if (pWav->container == drwav_container_aiff) {
7651 drwav_uint64 iSample;
7652 for (iSample = 0; iSample < samplesRead; iSample += 1) {
7653 pBufferOut[iSample] = -pBufferOut[iSample];
7654 }
7655 }
7656 }
7657 #endif
7658
7659 pBufferOut += samplesRead;
7660 framesToRead -= framesRead;
7661 totalFramesRead += framesRead;
7662 }
7663
7664 return totalFramesRead;
7665}
7666
7667DRWAV_PRIVATE drwav_uint64 drwav_read_pcm_frames_s32__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
7668{
7669 drwav_uint64 totalFramesRead;
7670 drwav_uint8 sampleData[4096] = {0};
7671 drwav_uint32 bytesPerFrame;
7672 drwav_uint32 bytesPerSample;
7673 drwav_uint64 samplesRead;
7674
7675 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav);
7676 if (bytesPerFrame == 0) {
7677 return 0;
7678 }
7679
7680 bytesPerSample = bytesPerFrame / pWav->channels;
7681 if (bytesPerSample == 0 || (bytesPerFrame % pWav->channels) != 0) {
7682 return 0; /* Only byte-aligned formats are supported. */
7683 }
7684
7685 totalFramesRead = 0;
7686
7687 while (framesToRead > 0) {
7688 drwav_uint64 framesToReadThisIteration = drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame);
7689 drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, framesToReadThisIteration, sampleData);
7690 if (framesRead == 0) {
7691 break;
7692 }
7693
7694 DRWAV_ASSERT(framesRead <= framesToReadThisIteration); /* If this fails it means there's a bug in drwav_read_pcm_frames(). */
7695
7696 /* Validation to ensure we don't read too much from out intermediary buffer. This is to protect from invalid files. */
7697 samplesRead = framesRead * pWav->channels;
7698 if ((samplesRead * bytesPerSample) > sizeof(sampleData)) {
7699 DRWAV_ASSERT(DRWAV_FALSE); /* This should never happen with a valid file. */
7700 break;
7701 }
7702
7703 drwav_mulaw_to_s32(pBufferOut, sampleData, (size_t)samplesRead);
7704
7705 #ifdef DR_WAV_LIBSNDFILE_COMPAT
7706 {
7707 if (pWav->container == drwav_container_aiff) {
7708 drwav_uint64 iSample;
7709 for (iSample = 0; iSample < samplesRead; iSample += 1) {
7710 pBufferOut[iSample] = -pBufferOut[iSample];
7711 }
7712 }
7713 }
7714 #endif
7715
7716 pBufferOut += samplesRead;
7717 framesToRead -= framesRead;
7718 totalFramesRead += framesRead;
7719 }
7720
7721 return totalFramesRead;
7722}
7723
7724DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
7725{
7726 if (pWav == NULL || framesToRead == 0) {
7727 return 0;
7728 }
7729
7730 if (pBufferOut == NULL) {
7731 return drwav_read_pcm_frames(pWav, framesToRead, NULL);
7732 }
7733
7734 /* Don't try to read more samples than can potentially fit in the output buffer. */
7735 if (framesToRead * pWav->channels * sizeof(drwav_int32) > DRWAV_SIZE_MAX) {
7736 framesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int32) / pWav->channels;
7737 }
7738
7739 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
7740 return drwav_read_pcm_frames_s32__pcm(pWav, framesToRead, pBufferOut);
7741 }
7742
7743 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
7744 return drwav_read_pcm_frames_s32__msadpcm_ima(pWav, framesToRead, pBufferOut);
7745 }
7746
7747 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
7748 return drwav_read_pcm_frames_s32__ieee(pWav, framesToRead, pBufferOut);
7749 }
7750
7751 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
7752 return drwav_read_pcm_frames_s32__alaw(pWav, framesToRead, pBufferOut);
7753 }
7754
7755 if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
7756 return drwav_read_pcm_frames_s32__mulaw(pWav, framesToRead, pBufferOut);
7757 }
7758
7759 return 0;
7760}
7761
7762DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
7763{
7764 drwav_uint64 framesRead = drwav_read_pcm_frames_s32(pWav, framesToRead, pBufferOut);
7765 if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) {
7766 drwav__bswap_samples_s32(pBufferOut, framesRead*pWav->channels);
7767 }
7768
7769 return framesRead;
7770}
7771
7772DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut)
7773{
7774 drwav_uint64 framesRead = drwav_read_pcm_frames_s32(pWav, framesToRead, pBufferOut);
7775 if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) {
7776 drwav__bswap_samples_s32(pBufferOut, framesRead*pWav->channels);
7777 }
7778
7779 return framesRead;
7780}
7781
7782
7783DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
7784{
7785 size_t i;
7786
7787 if (pOut == NULL || pIn == NULL) {
7788 return;
7789 }
7790
7791 for (i = 0; i < sampleCount; ++i) {
7792 *pOut++ = ((int)pIn[i] - 128) << 24;
7793 }
7794}
7795
7796DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount)
7797{
7798 size_t i;
7799
7800 if (pOut == NULL || pIn == NULL) {
7801 return;
7802 }
7803
7804 for (i = 0; i < sampleCount; ++i) {
7805 *pOut++ = pIn[i] << 16;
7806 }
7807}
7808
7809DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
7810{
7811 size_t i;
7812
7813 if (pOut == NULL || pIn == NULL) {
7814 return;
7815 }
7816
7817 for (i = 0; i < sampleCount; ++i) {
7818 unsigned int s0 = pIn[i*3 + 0];
7819 unsigned int s1 = pIn[i*3 + 1];
7820 unsigned int s2 = pIn[i*3 + 2];
7821
7822 drwav_int32 sample32 = (drwav_int32)((s0 << 8) | (s1 << 16) | (s2 << 24));
7823 *pOut++ = sample32;
7824 }
7825}
7826
7827DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount)
7828{
7829 size_t i;
7830
7831 if (pOut == NULL || pIn == NULL) {
7832 return;
7833 }
7834
7835 for (i = 0; i < sampleCount; ++i) {
7836 *pOut++ = (drwav_int32)(2147483648.0f * pIn[i]);
7837 }
7838}
7839
7840DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount)
7841{
7842 size_t i;
7843
7844 if (pOut == NULL || pIn == NULL) {
7845 return;
7846 }
7847
7848 for (i = 0; i < sampleCount; ++i) {
7849 *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]);
7850 }
7851}
7852
7853DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
7854{
7855 size_t i;
7856
7857 if (pOut == NULL || pIn == NULL) {
7858 return;
7859 }
7860
7861 for (i = 0; i < sampleCount; ++i) {
7862 *pOut++ = ((drwav_int32)drwav__alaw_to_s16(pIn[i])) << 16;
7863 }
7864}
7865
7866DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
7867{
7868 size_t i;
7869
7870 if (pOut == NULL || pIn == NULL) {
7871 return;
7872 }
7873
7874 for (i= 0; i < sampleCount; ++i) {
7875 *pOut++ = ((drwav_int32)drwav__mulaw_to_s16(pIn[i])) << 16;
7876 }
7877}
7878
7879
7880
7881DRWAV_PRIVATE drwav_int16* drwav__read_pcm_frames_and_close_s16(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
7882{
7883 drwav_uint64 sampleDataSize;
7884 drwav_int16* pSampleData;
7885 drwav_uint64 framesRead;
7886
7887 DRWAV_ASSERT(pWav != NULL);
7888
7889 sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int16);
7890 if (sampleDataSize > DRWAV_SIZE_MAX) {
7891 drwav_uninit(pWav);
7892 return NULL; /* File's too big. */
7893 }
7894
7895 pSampleData = (drwav_int16*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */
7896 if (pSampleData == NULL) {
7897 drwav_uninit(pWav);
7898 return NULL; /* Failed to allocate memory. */
7899 }
7900
7901 framesRead = drwav_read_pcm_frames_s16(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData);
7902 if (framesRead != pWav->totalPCMFrameCount) {
7903 drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks);
7904 drwav_uninit(pWav);
7905 return NULL; /* There was an error reading the samples. */
7906 }
7907
7908 drwav_uninit(pWav);
7909
7910 if (sampleRate) {
7911 *sampleRate = pWav->sampleRate;
7912 }
7913 if (channels) {
7914 *channels = pWav->channels;
7915 }
7916 if (totalFrameCount) {
7917 *totalFrameCount = pWav->totalPCMFrameCount;
7918 }
7919
7920 return pSampleData;
7921}
7922
7923DRWAV_PRIVATE float* drwav__read_pcm_frames_and_close_f32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
7924{
7925 drwav_uint64 sampleDataSize;
7926 float* pSampleData;
7927 drwav_uint64 framesRead;
7928
7929 DRWAV_ASSERT(pWav != NULL);
7930
7931 sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(float);
7932 if (sampleDataSize > DRWAV_SIZE_MAX) {
7933 drwav_uninit(pWav);
7934 return NULL; /* File's too big. */
7935 }
7936
7937 pSampleData = (float*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */
7938 if (pSampleData == NULL) {
7939 drwav_uninit(pWav);
7940 return NULL; /* Failed to allocate memory. */
7941 }
7942
7943 framesRead = drwav_read_pcm_frames_f32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData);
7944 if (framesRead != pWav->totalPCMFrameCount) {
7945 drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks);
7946 drwav_uninit(pWav);
7947 return NULL; /* There was an error reading the samples. */
7948 }
7949
7950 drwav_uninit(pWav);
7951
7952 if (sampleRate) {
7953 *sampleRate = pWav->sampleRate;
7954 }
7955 if (channels) {
7956 *channels = pWav->channels;
7957 }
7958 if (totalFrameCount) {
7959 *totalFrameCount = pWav->totalPCMFrameCount;
7960 }
7961
7962 return pSampleData;
7963}
7964
7965DRWAV_PRIVATE drwav_int32* drwav__read_pcm_frames_and_close_s32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount)
7966{
7967 drwav_uint64 sampleDataSize;
7968 drwav_int32* pSampleData;
7969 drwav_uint64 framesRead;
7970
7971 DRWAV_ASSERT(pWav != NULL);
7972
7973 sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int32);
7974 if (sampleDataSize > DRWAV_SIZE_MAX) {
7975 drwav_uninit(pWav);
7976 return NULL; /* File's too big. */
7977 }
7978
7979 pSampleData = (drwav_int32*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */
7980 if (pSampleData == NULL) {
7981 drwav_uninit(pWav);
7982 return NULL; /* Failed to allocate memory. */
7983 }
7984
7985 framesRead = drwav_read_pcm_frames_s32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData);
7986 if (framesRead != pWav->totalPCMFrameCount) {
7987 drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks);
7988 drwav_uninit(pWav);
7989 return NULL; /* There was an error reading the samples. */
7990 }
7991
7992 drwav_uninit(pWav);
7993
7994 if (sampleRate) {
7995 *sampleRate = pWav->sampleRate;
7996 }
7997 if (channels) {
7998 *channels = pWav->channels;
7999 }
8000 if (totalFrameCount) {
8001 *totalFrameCount = pWav->totalPCMFrameCount;
8002 }
8003
8004 return pSampleData;
8005}
8006
8007
8008
8009DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
8010{
8011 drwav wav;
8012
8013 if (channelsOut) {
8014 *channelsOut = 0;
8015 }
8016 if (sampleRateOut) {
8017 *sampleRateOut = 0;
8018 }
8019 if (totalFrameCountOut) {
8020 *totalFrameCountOut = 0;
8021 }
8022
8023 if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
8024 return NULL;
8025 }
8026
8027 return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
8028}
8029
8030DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
8031{
8032 drwav wav;
8033
8034 if (channelsOut) {
8035 *channelsOut = 0;
8036 }
8037 if (sampleRateOut) {
8038 *sampleRateOut = 0;
8039 }
8040 if (totalFrameCountOut) {
8041 *totalFrameCountOut = 0;
8042 }
8043
8044 if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
8045 return NULL;
8046 }
8047
8048 return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
8049}
8050
8051DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
8052{
8053 drwav wav;
8054
8055 if (channelsOut) {
8056 *channelsOut = 0;
8057 }
8058 if (sampleRateOut) {
8059 *sampleRateOut = 0;
8060 }
8061 if (totalFrameCountOut) {
8062 *totalFrameCountOut = 0;
8063 }
8064
8065 if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) {
8066 return NULL;
8067 }
8068
8069 return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
8070}
8071
8072#ifndef DR_WAV_NO_STDIO
8073DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
8074{
8075 drwav wav;
8076
8077 if (channelsOut) {
8078 *channelsOut = 0;
8079 }
8080 if (sampleRateOut) {
8081 *sampleRateOut = 0;
8082 }
8083 if (totalFrameCountOut) {
8084 *totalFrameCountOut = 0;
8085 }
8086
8087 if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
8088 return NULL;
8089 }
8090
8091 return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
8092}
8093
8094DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
8095{
8096 drwav wav;
8097
8098 if (channelsOut) {
8099 *channelsOut = 0;
8100 }
8101 if (sampleRateOut) {
8102 *sampleRateOut = 0;
8103 }
8104 if (totalFrameCountOut) {
8105 *totalFrameCountOut = 0;
8106 }
8107
8108 if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
8109 return NULL;
8110 }
8111
8112 return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
8113}
8114
8115DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
8116{
8117 drwav wav;
8118
8119 if (channelsOut) {
8120 *channelsOut = 0;
8121 }
8122 if (sampleRateOut) {
8123 *sampleRateOut = 0;
8124 }
8125 if (totalFrameCountOut) {
8126 *totalFrameCountOut = 0;
8127 }
8128
8129 if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) {
8130 return NULL;
8131 }
8132
8133 return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
8134}
8135
8136
8137#ifndef DR_WAV_NO_WCHAR
8138DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
8139{
8140 drwav wav;
8141
8142 if (sampleRateOut) {
8143 *sampleRateOut = 0;
8144 }
8145 if (channelsOut) {
8146 *channelsOut = 0;
8147 }
8148 if (totalFrameCountOut) {
8149 *totalFrameCountOut = 0;
8150 }
8151
8152 if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
8153 return NULL;
8154 }
8155
8156 return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
8157}
8158
8159DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
8160{
8161 drwav wav;
8162
8163 if (sampleRateOut) {
8164 *sampleRateOut = 0;
8165 }
8166 if (channelsOut) {
8167 *channelsOut = 0;
8168 }
8169 if (totalFrameCountOut) {
8170 *totalFrameCountOut = 0;
8171 }
8172
8173 if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
8174 return NULL;
8175 }
8176
8177 return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
8178}
8179
8180DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
8181{
8182 drwav wav;
8183
8184 if (sampleRateOut) {
8185 *sampleRateOut = 0;
8186 }
8187 if (channelsOut) {
8188 *channelsOut = 0;
8189 }
8190 if (totalFrameCountOut) {
8191 *totalFrameCountOut = 0;
8192 }
8193
8194 if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) {
8195 return NULL;
8196 }
8197
8198 return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
8199}
8200#endif /* DR_WAV_NO_WCHAR */
8201#endif /* DR_WAV_NO_STDIO */
8202
8203DRWAV_API drwav_int16* drwav_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
8204{
8205 drwav wav;
8206
8207 if (channelsOut) {
8208 *channelsOut = 0;
8209 }
8210 if (sampleRateOut) {
8211 *sampleRateOut = 0;
8212 }
8213 if (totalFrameCountOut) {
8214 *totalFrameCountOut = 0;
8215 }
8216
8217 if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
8218 return NULL;
8219 }
8220
8221 return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
8222}
8223
8224DRWAV_API float* drwav_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
8225{
8226 drwav wav;
8227
8228 if (channelsOut) {
8229 *channelsOut = 0;
8230 }
8231 if (sampleRateOut) {
8232 *sampleRateOut = 0;
8233 }
8234 if (totalFrameCountOut) {
8235 *totalFrameCountOut = 0;
8236 }
8237
8238 if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
8239 return NULL;
8240 }
8241
8242 return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
8243}
8244
8245DRWAV_API drwav_int32* drwav_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
8246{
8247 drwav wav;
8248
8249 if (channelsOut) {
8250 *channelsOut = 0;
8251 }
8252 if (sampleRateOut) {
8253 *sampleRateOut = 0;
8254 }
8255 if (totalFrameCountOut) {
8256 *totalFrameCountOut = 0;
8257 }
8258
8259 if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) {
8260 return NULL;
8261 }
8262
8263 return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
8264}
8265#endif /* DR_WAV_NO_CONVERSION_API */
8266
8267
8268DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks)
8269{
8270 if (pAllocationCallbacks != NULL) {
8271 drwav__free_from_callbacks(p, pAllocationCallbacks);
8272 } else {
8273 drwav__free_default(p, NULL);
8274 }
8275}
8276
8277DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data)
8278{
8279 return ((drwav_uint16)data[0] << 0) | ((drwav_uint16)data[1] << 8);
8280}
8281
8282DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data)
8283{
8284 return (drwav_int16)drwav_bytes_to_u16(data);
8285}
8286
8287DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data)
8288{
8289 return drwav_bytes_to_u32_le(data);
8290}
8291
8292DRWAV_API float drwav_bytes_to_f32(const drwav_uint8* data)
8293{
8294 union {
8295 drwav_uint32 u32;
8296 float f32;
8297 } value;
8298
8299 value.u32 = drwav_bytes_to_u32(data);
8300 return value.f32;
8301}
8302
8303DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data)
8304{
8305 return (drwav_int32)drwav_bytes_to_u32(data);
8306}
8307
8308DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data)
8309{
8310 return
8311 ((drwav_uint64)data[0] << 0) | ((drwav_uint64)data[1] << 8) | ((drwav_uint64)data[2] << 16) | ((drwav_uint64)data[3] << 24) |
8312 ((drwav_uint64)data[4] << 32) | ((drwav_uint64)data[5] << 40) | ((drwav_uint64)data[6] << 48) | ((drwav_uint64)data[7] << 56);
8313}
8314
8315DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data)
8316{
8317 return (drwav_int64)drwav_bytes_to_u64(data);
8318}
8319
8320
8321DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16])
8322{
8323 int i;
8324 for (i = 0; i < 16; i += 1) {
8325 if (a[i] != b[i]) {
8326 return DRWAV_FALSE;
8327 }
8328 }
8329
8330 return DRWAV_TRUE;
8331}
8332
8333DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b)
8334{
8335 return
8336 a[0] == b[0] &&
8337 a[1] == b[1] &&
8338 a[2] == b[2] &&
8339 a[3] == b[3];
8340}
8341
8342#ifdef __MRC__
8343/* Undo the pragma at the beginning of this file. */
8344#pragma options opt reset
8345#endif
8346
8347#endif /* dr_wav_c */
8348#endif /* DR_WAV_IMPLEMENTATION */
8349
8350/*
8351REVISION HISTORY
8352================
8353v0.13.16 - 2024-02-27
8354 - Fix a Wdouble-promotion warning.
8355
8356v0.13.15 - 2024-01-23
8357 - Relax some unnecessary validation that prevented some files from loading.
8358
8359v0.13.14 - 2023-12-02
8360 - Fix a warning about an unused variable.
8361
8362v0.13.13 - 2023-11-02
8363 - Fix a warning when compiling with Clang.
8364
8365v0.13.12 - 2023-08-07
8366 - Fix a possible crash in drwav_read_pcm_frames().
8367
8368v0.13.11 - 2023-07-07
8369 - AIFF compatibility improvements.
8370
8371v0.13.10 - 2023-05-29
8372 - Fix a bug where drwav_init_with_metadata() does not decode any frames after initializtion.
8373
8374v0.13.9 - 2023-05-22
8375 - Add support for AIFF decoding (writing and metadata not supported).
8376 - Add support for RIFX decoding (writing and metadata not supported).
8377 - Fix a bug where metadata is not processed if it's located before the "fmt " chunk.
8378 - Add a workaround for a type of malformed WAV file where the size of the "RIFF" and "data" chunks
8379 are incorrectly set to 0xFFFFFFFF.
8380
8381v0.13.8 - 2023-03-25
8382 - Fix a possible null pointer dereference.
8383 - Fix a crash when loading files with badly formed metadata.
8384
8385v0.13.7 - 2022-09-17
8386 - Fix compilation with DJGPP.
8387 - Add support for disabling wchar_t with DR_WAV_NO_WCHAR.
8388
8389v0.13.6 - 2022-04-10
8390 - Fix compilation error on older versions of GCC.
8391 - Remove some dependencies on the standard library.
8392
8393v0.13.5 - 2022-01-26
8394 - Fix an error when seeking to the end of the file.
8395
8396v0.13.4 - 2021-12-08
8397 - Fix some static analysis warnings.
8398
8399v0.13.3 - 2021-11-24
8400 - Fix an incorrect assertion when trying to endian swap 1-byte sample formats. This is now a no-op
8401 rather than a failed assertion.
8402 - Fix a bug with parsing of the bext chunk.
8403 - Fix some static analysis warnings.
8404
8405v0.13.2 - 2021-10-02
8406 - Fix a possible buffer overflow when reading from compressed formats.
8407
8408v0.13.1 - 2021-07-31
8409 - Fix platform detection for ARM64.
8410
8411v0.13.0 - 2021-07-01
8412 - Improve support for reading and writing metadata. Use the `_with_metadata()` APIs to initialize
8413 a WAV decoder and store the metadata within the `drwav` object. Use the `pMetadata` and
8414 `metadataCount` members of the `drwav` object to read the data. The old way of handling metadata
8415 via a callback is still usable and valid.
8416 - API CHANGE: drwav_target_write_size_bytes() now takes extra parameters for calculating the
8417 required write size when writing metadata.
8418 - Add drwav_get_cursor_in_pcm_frames()
8419 - Add drwav_get_length_in_pcm_frames()
8420 - Fix a bug where drwav_read_raw() can call the read callback with a byte count of zero.
8421
8422v0.12.20 - 2021-06-11
8423 - Fix some undefined behavior.
8424
8425v0.12.19 - 2021-02-21
8426 - Fix a warning due to referencing _MSC_VER when it is undefined.
8427 - Minor improvements to the management of some internal state concerning the data chunk cursor.
8428
8429v0.12.18 - 2021-01-31
8430 - Clean up some static analysis warnings.
8431
8432v0.12.17 - 2021-01-17
8433 - Minor fix to sample code in documentation.
8434 - Correctly qualify a private API as private rather than public.
8435 - Code cleanup.
8436
8437v0.12.16 - 2020-12-02
8438 - Fix a bug when trying to read more bytes than can fit in a size_t.
8439
8440v0.12.15 - 2020-11-21
8441 - Fix compilation with OpenWatcom.
8442
8443v0.12.14 - 2020-11-13
8444 - Minor code clean up.
8445
8446v0.12.13 - 2020-11-01
8447 - Improve compiler support for older versions of GCC.
8448
8449v0.12.12 - 2020-09-28
8450 - Add support for RF64.
8451 - Fix a bug in writing mode where the size of the RIFF chunk incorrectly includes the header section.
8452
8453v0.12.11 - 2020-09-08
8454 - Fix a compilation error on older compilers.
8455
8456v0.12.10 - 2020-08-24
8457 - Fix a bug when seeking with ADPCM formats.
8458
8459v0.12.9 - 2020-08-02
8460 - Simplify sized types.
8461
8462v0.12.8 - 2020-07-25
8463 - Fix a compilation warning.
8464
8465v0.12.7 - 2020-07-15
8466 - Fix some bugs on big-endian architectures.
8467 - Fix an error in s24 to f32 conversion.
8468
8469v0.12.6 - 2020-06-23
8470 - Change drwav_read_*() to allow NULL to be passed in as the output buffer which is equivalent to a forward seek.
8471 - Fix a buffer overflow when trying to decode invalid IMA-ADPCM files.
8472 - Add include guard for the implementation section.
8473
8474v0.12.5 - 2020-05-27
8475 - Minor documentation fix.
8476
8477v0.12.4 - 2020-05-16
8478 - Replace assert() with DRWAV_ASSERT().
8479 - Add compile-time and run-time version querying.
8480 - DRWAV_VERSION_MINOR
8481 - DRWAV_VERSION_MAJOR
8482 - DRWAV_VERSION_REVISION
8483 - DRWAV_VERSION_STRING
8484 - drwav_version()
8485 - drwav_version_string()
8486
8487v0.12.3 - 2020-04-30
8488 - Fix compilation errors with VC6.
8489
8490v0.12.2 - 2020-04-21
8491 - Fix a bug where drwav_init_file() does not close the file handle after attempting to load an erroneous file.
8492
8493v0.12.1 - 2020-04-13
8494 - Fix some pedantic warnings.
8495
8496v0.12.0 - 2020-04-04
8497 - API CHANGE: Add container and format parameters to the chunk callback.
8498 - Minor documentation updates.
8499
8500v0.11.5 - 2020-03-07
8501 - Fix compilation error with Visual Studio .NET 2003.
8502
8503v0.11.4 - 2020-01-29
8504 - Fix some static analysis warnings.
8505 - Fix a bug when reading f32 samples from an A-law encoded stream.
8506
8507v0.11.3 - 2020-01-12
8508 - Minor changes to some f32 format conversion routines.
8509 - Minor bug fix for ADPCM conversion when end of file is reached.
8510
8511v0.11.2 - 2019-12-02
8512 - Fix a possible crash when using custom memory allocators without a custom realloc() implementation.
8513 - Fix an integer overflow bug.
8514 - Fix a null pointer dereference bug.
8515 - Add limits to sample rate, channels and bits per sample to tighten up some validation.
8516
8517v0.11.1 - 2019-10-07
8518 - Internal code clean up.
8519
8520v0.11.0 - 2019-10-06
8521 - API CHANGE: Add support for user defined memory allocation routines. This system allows the program to specify their own memory allocation
8522 routines with a user data pointer for client-specific contextual data. This adds an extra parameter to the end of the following APIs:
8523 - drwav_init()
8524 - drwav_init_ex()
8525 - drwav_init_file()
8526 - drwav_init_file_ex()
8527 - drwav_init_file_w()
8528 - drwav_init_file_w_ex()
8529 - drwav_init_memory()
8530 - drwav_init_memory_ex()
8531 - drwav_init_write()
8532 - drwav_init_write_sequential()
8533 - drwav_init_write_sequential_pcm_frames()
8534 - drwav_init_file_write()
8535 - drwav_init_file_write_sequential()
8536 - drwav_init_file_write_sequential_pcm_frames()
8537 - drwav_init_file_write_w()
8538 - drwav_init_file_write_sequential_w()
8539 - drwav_init_file_write_sequential_pcm_frames_w()
8540 - drwav_init_memory_write()
8541 - drwav_init_memory_write_sequential()
8542 - drwav_init_memory_write_sequential_pcm_frames()
8543 - drwav_open_and_read_pcm_frames_s16()
8544 - drwav_open_and_read_pcm_frames_f32()
8545 - drwav_open_and_read_pcm_frames_s32()
8546 - drwav_open_file_and_read_pcm_frames_s16()
8547 - drwav_open_file_and_read_pcm_frames_f32()
8548 - drwav_open_file_and_read_pcm_frames_s32()
8549 - drwav_open_file_and_read_pcm_frames_s16_w()
8550 - drwav_open_file_and_read_pcm_frames_f32_w()
8551 - drwav_open_file_and_read_pcm_frames_s32_w()
8552 - drwav_open_memory_and_read_pcm_frames_s16()
8553 - drwav_open_memory_and_read_pcm_frames_f32()
8554 - drwav_open_memory_and_read_pcm_frames_s32()
8555 Set this extra parameter to NULL to use defaults which is the same as the previous behaviour. Setting this NULL will use
8556 DRWAV_MALLOC, DRWAV_REALLOC and DRWAV_FREE.
8557 - Add support for reading and writing PCM frames in an explicit endianness. New APIs:
8558 - drwav_read_pcm_frames_le()
8559 - drwav_read_pcm_frames_be()
8560 - drwav_read_pcm_frames_s16le()
8561 - drwav_read_pcm_frames_s16be()
8562 - drwav_read_pcm_frames_f32le()
8563 - drwav_read_pcm_frames_f32be()
8564 - drwav_read_pcm_frames_s32le()
8565 - drwav_read_pcm_frames_s32be()
8566 - drwav_write_pcm_frames_le()
8567 - drwav_write_pcm_frames_be()
8568 - Remove deprecated APIs.
8569 - API CHANGE: The following APIs now return native-endian data. Previously they returned little-endian data.
8570 - drwav_read_pcm_frames()
8571 - drwav_read_pcm_frames_s16()
8572 - drwav_read_pcm_frames_s32()
8573 - drwav_read_pcm_frames_f32()
8574 - drwav_open_and_read_pcm_frames_s16()
8575 - drwav_open_and_read_pcm_frames_s32()
8576 - drwav_open_and_read_pcm_frames_f32()
8577 - drwav_open_file_and_read_pcm_frames_s16()
8578 - drwav_open_file_and_read_pcm_frames_s32()
8579 - drwav_open_file_and_read_pcm_frames_f32()
8580 - drwav_open_file_and_read_pcm_frames_s16_w()
8581 - drwav_open_file_and_read_pcm_frames_s32_w()
8582 - drwav_open_file_and_read_pcm_frames_f32_w()
8583 - drwav_open_memory_and_read_pcm_frames_s16()
8584 - drwav_open_memory_and_read_pcm_frames_s32()
8585 - drwav_open_memory_and_read_pcm_frames_f32()
8586
8587v0.10.1 - 2019-08-31
8588 - Correctly handle partial trailing ADPCM blocks.
8589
8590v0.10.0 - 2019-08-04
8591 - Remove deprecated APIs.
8592 - Add wchar_t variants for file loading APIs:
8593 drwav_init_file_w()
8594 drwav_init_file_ex_w()
8595 drwav_init_file_write_w()
8596 drwav_init_file_write_sequential_w()
8597 - Add drwav_target_write_size_bytes() which calculates the total size in bytes of a WAV file given a format and sample count.
8598 - Add APIs for specifying the PCM frame count instead of the sample count when opening in sequential write mode:
8599 drwav_init_write_sequential_pcm_frames()
8600 drwav_init_file_write_sequential_pcm_frames()
8601 drwav_init_file_write_sequential_pcm_frames_w()
8602 drwav_init_memory_write_sequential_pcm_frames()
8603 - Deprecate drwav_open*() and drwav_close():
8604 drwav_open()
8605 drwav_open_ex()
8606 drwav_open_write()
8607 drwav_open_write_sequential()
8608 drwav_open_file()
8609 drwav_open_file_ex()
8610 drwav_open_file_write()
8611 drwav_open_file_write_sequential()
8612 drwav_open_memory()
8613 drwav_open_memory_ex()
8614 drwav_open_memory_write()
8615 drwav_open_memory_write_sequential()
8616 drwav_close()
8617 - Minor documentation updates.
8618
8619v0.9.2 - 2019-05-21
8620 - Fix warnings.
8621
8622v0.9.1 - 2019-05-05
8623 - Add support for C89.
8624 - Change license to choice of public domain or MIT-0.
8625
8626v0.9.0 - 2018-12-16
8627 - API CHANGE: Add new reading APIs for reading by PCM frames instead of samples. Old APIs have been deprecated and
8628 will be removed in v0.10.0. Deprecated APIs and their replacements:
8629 drwav_read() -> drwav_read_pcm_frames()
8630 drwav_read_s16() -> drwav_read_pcm_frames_s16()
8631 drwav_read_f32() -> drwav_read_pcm_frames_f32()
8632 drwav_read_s32() -> drwav_read_pcm_frames_s32()
8633 drwav_seek_to_sample() -> drwav_seek_to_pcm_frame()
8634 drwav_write() -> drwav_write_pcm_frames()
8635 drwav_open_and_read_s16() -> drwav_open_and_read_pcm_frames_s16()
8636 drwav_open_and_read_f32() -> drwav_open_and_read_pcm_frames_f32()
8637 drwav_open_and_read_s32() -> drwav_open_and_read_pcm_frames_s32()
8638 drwav_open_file_and_read_s16() -> drwav_open_file_and_read_pcm_frames_s16()
8639 drwav_open_file_and_read_f32() -> drwav_open_file_and_read_pcm_frames_f32()
8640 drwav_open_file_and_read_s32() -> drwav_open_file_and_read_pcm_frames_s32()
8641 drwav_open_memory_and_read_s16() -> drwav_open_memory_and_read_pcm_frames_s16()
8642 drwav_open_memory_and_read_f32() -> drwav_open_memory_and_read_pcm_frames_f32()
8643 drwav_open_memory_and_read_s32() -> drwav_open_memory_and_read_pcm_frames_s32()
8644 drwav::totalSampleCount -> drwav::totalPCMFrameCount
8645 - API CHANGE: Rename drwav_open_and_read_file_*() to drwav_open_file_and_read_*().
8646 - API CHANGE: Rename drwav_open_and_read_memory_*() to drwav_open_memory_and_read_*().
8647 - Add built-in support for smpl chunks.
8648 - Add support for firing a callback for each chunk in the file at initialization time.
8649 - This is enabled through the drwav_init_ex(), etc. family of APIs.
8650 - Handle invalid FMT chunks more robustly.
8651
8652v0.8.5 - 2018-09-11
8653 - Const correctness.
8654 - Fix a potential stack overflow.
8655
8656v0.8.4 - 2018-08-07
8657 - Improve 64-bit detection.
8658
8659v0.8.3 - 2018-08-05
8660 - Fix C++ build on older versions of GCC.
8661
8662v0.8.2 - 2018-08-02
8663 - Fix some big-endian bugs.
8664
8665v0.8.1 - 2018-06-29
8666 - Add support for sequential writing APIs.
8667 - Disable seeking in write mode.
8668 - Fix bugs with Wave64.
8669 - Fix typos.
8670
8671v0.8 - 2018-04-27
8672 - Bug fix.
8673 - Start using major.minor.revision versioning.
8674
8675v0.7f - 2018-02-05
8676 - Restrict ADPCM formats to a maximum of 2 channels.
8677
8678v0.7e - 2018-02-02
8679 - Fix a crash.
8680
8681v0.7d - 2018-02-01
8682 - Fix a crash.
8683
8684v0.7c - 2018-02-01
8685 - Set drwav.bytesPerSample to 0 for all compressed formats.
8686 - Fix a crash when reading 16-bit floating point WAV files. In this case dr_wav will output silence for
8687 all format conversion reading APIs (*_s16, *_s32, *_f32 APIs).
8688 - Fix some divide-by-zero errors.
8689
8690v0.7b - 2018-01-22
8691 - Fix errors with seeking of compressed formats.
8692 - Fix compilation error when DR_WAV_NO_CONVERSION_API
8693
8694v0.7a - 2017-11-17
8695 - Fix some GCC warnings.
8696
8697v0.7 - 2017-11-04
8698 - Add writing APIs.
8699
8700v0.6 - 2017-08-16
8701 - API CHANGE: Rename dr_* types to drwav_*.
8702 - Add support for custom implementations of malloc(), realloc(), etc.
8703 - Add support for Microsoft ADPCM.
8704 - Add support for IMA ADPCM (DVI, format code 0x11).
8705 - Optimizations to drwav_read_s16().
8706 - Bug fixes.
8707
8708v0.5g - 2017-07-16
8709 - Change underlying type for booleans to unsigned.
8710
8711v0.5f - 2017-04-04
8712 - Fix a minor bug with drwav_open_and_read_s16() and family.
8713
8714v0.5e - 2016-12-29
8715 - Added support for reading samples as signed 16-bit integers. Use the _s16() family of APIs for this.
8716 - Minor fixes to documentation.
8717
8718v0.5d - 2016-12-28
8719 - Use drwav_int* and drwav_uint* sized types to improve compiler support.
8720
8721v0.5c - 2016-11-11
8722 - Properly handle JUNK chunks that come before the FMT chunk.
8723
8724v0.5b - 2016-10-23
8725 - A minor change to drwav_bool8 and drwav_bool32 types.
8726
8727v0.5a - 2016-10-11
8728 - Fixed a bug with drwav_open_and_read() and family due to incorrect argument ordering.
8729 - Improve A-law and mu-law efficiency.
8730
8731v0.5 - 2016-09-29
8732 - API CHANGE. Swap the order of "channels" and "sampleRate" parameters in drwav_open_and_read*(). Rationale for this is to
8733 keep it consistent with dr_audio and dr_flac.
8734
8735v0.4b - 2016-09-18
8736 - Fixed a typo in documentation.
8737
8738v0.4a - 2016-09-18
8739 - Fixed a typo.
8740 - Change date format to ISO 8601 (YYYY-MM-DD)
8741
8742v0.4 - 2016-07-13
8743 - API CHANGE. Make onSeek consistent with dr_flac.
8744 - API CHANGE. Rename drwav_seek() to drwav_seek_to_sample() for clarity and consistency with dr_flac.
8745 - Added support for Sony Wave64.
8746
8747v0.3a - 2016-05-28
8748 - API CHANGE. Return drwav_bool32 instead of int in onSeek callback.
8749 - Fixed a memory leak.
8750
8751v0.3 - 2016-05-22
8752 - Lots of API changes for consistency.
8753
8754v0.2a - 2016-05-16
8755 - Fixed Linux/GCC build.
8756
8757v0.2 - 2016-05-11
8758 - Added support for reading data as signed 32-bit PCM for consistency with dr_flac.
8759
8760v0.1a - 2016-05-07
8761 - Fixed a bug in drwav_open_file() where the file handle would not be closed if the loader failed to initialize.
8762
8763v0.1 - 2016-05-04
8764 - Initial versioned release.
8765*/
8766
8767/*
8768This software is available as a choice of the following licenses. Choose
8769whichever you prefer.
8770
8771===============================================================================
8772ALTERNATIVE 1 - Public Domain (www.unlicense.org)
8773===============================================================================
8774This is free and unencumbered software released into the public domain.
8775
8776Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
8777software, either in source code form or as a compiled binary, for any purpose,
8778commercial or non-commercial, and by any means.
8779
8780In jurisdictions that recognize copyright laws, the author or authors of this
8781software dedicate any and all copyright interest in the software to the public
8782domain. We make this dedication for the benefit of the public at large and to
8783the detriment of our heirs and successors. We intend this dedication to be an
8784overt act of relinquishment in perpetuity of all present and future rights to
8785this software under copyright law.
8786
8787THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
8788IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
8789FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
8790AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
8791ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
8792WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8793
8794For more information, please refer to <http://unlicense.org/>
8795
8796===============================================================================
8797ALTERNATIVE 2 - MIT No Attribution
8798===============================================================================
8799Copyright 2023 David Reid
8800
8801Permission is hereby granted, free of charge, to any person obtaining a copy of
8802this software and associated documentation files (the "Software"), to deal in
8803the Software without restriction, including without limitation the rights to
8804use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8805of the Software, and to permit persons to whom the Software is furnished to do
8806so.
8807
8808THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
8809IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
8810FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
8811AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
8812LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
8813OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
8814SOFTWARE.
8815*/
diff --git a/raylib/src/external/glad.h b/raylib/src/external/glad.h
new file mode 100644
index 0000000..5bb79d4
--- /dev/null
+++ b/raylib/src/external/glad.h
@@ -0,0 +1,8682 @@
1/**
2 * Loader generated by glad 2.0.0-beta on Sun Sep 18 18:12:12 2022
3 *
4 * Generator: C/C++
5 * Specification: gl
6 * Extensions: 116
7 *
8 * APIs:
9 * - gl:core=4.3
10 *
11 * Options:
12 * - ALIAS = False
13 * - DEBUG = False
14 * - HEADER_ONLY = True
15 * - LOADER = False
16 * - MX = False
17 * - MX_GLOBAL = False
18 * - ON_DEMAND = False
19 *
20 * Commandline:
21 * --api='gl:core=4.3' --extensions='GL_ARB_ES2_compatibility,GL_ARB_ES3_1_compatibility,GL_ARB_ES3_2_compatibility,GL_ARB_ES3_compatibility,GL_ARB_blend_func_extended,GL_ARB_buffer_storage,GL_ARB_clear_buffer_object,GL_ARB_clear_texture,GL_ARB_color_buffer_float,GL_ARB_compatibility,GL_ARB_compressed_texture_pixel_storage,GL_ARB_compute_shader,GL_ARB_compute_variable_group_size,GL_ARB_copy_buffer,GL_ARB_copy_image,GL_ARB_debug_output,GL_ARB_depth_buffer_float,GL_ARB_depth_clamp,GL_ARB_depth_texture,GL_ARB_direct_state_access,GL_ARB_draw_buffers,GL_ARB_draw_buffers_blend,GL_ARB_draw_elements_base_vertex,GL_ARB_draw_indirect,GL_ARB_draw_instanced,GL_ARB_enhanced_layouts,GL_ARB_explicit_attrib_location,GL_ARB_explicit_uniform_location,GL_ARB_fragment_coord_conventions,GL_ARB_fragment_layer_viewport,GL_ARB_fragment_program,GL_ARB_fragment_program_shadow,GL_ARB_fragment_shader,GL_ARB_fragment_shader_interlock,GL_ARB_framebuffer_no_attachments,GL_ARB_framebuffer_object,GL_ARB_framebuffer_sRGB,GL_ARB_geometry_shader4,GL_ARB_get_program_binary,GL_ARB_get_texture_sub_image,GL_ARB_gl_spirv,GL_ARB_gpu_shader5,GL_ARB_gpu_shader_fp64,GL_ARB_gpu_shader_int64,GL_ARB_half_float_pixel,GL_ARB_half_float_vertex,GL_ARB_instanced_arrays,GL_ARB_internalformat_query,GL_ARB_internalformat_query2,GL_ARB_map_buffer_range,GL_ARB_multi_bind,GL_ARB_multi_draw_indirect,GL_ARB_multisample,GL_ARB_multitexture,GL_ARB_occlusion_query,GL_ARB_occlusion_query2,GL_ARB_pipeline_statistics_query,GL_ARB_query_buffer_object,GL_ARB_sample_locations,GL_ARB_sample_shading,GL_ARB_seamless_cube_map,GL_ARB_seamless_cubemap_per_texture,GL_ARB_shader_atomic_counter_ops,GL_ARB_shader_atomic_counters,GL_ARB_shader_bit_encoding,GL_ARB_shader_clock,GL_ARB_shader_image_load_store,GL_ARB_shader_image_size,GL_ARB_shader_objects,GL_ARB_shader_storage_buffer_object,GL_ARB_shader_texture_lod,GL_ARB_shading_language_100,GL_ARB_shading_language_420pack,GL_ARB_shading_language_include,GL_ARB_shading_language_packing,GL_ARB_spirv_extensions,GL_ARB_tessellation_shader,GL_ARB_texture_border_clamp,GL_ARB_texture_buffer_object_rgb32,GL_ARB_texture_compression,GL_ARB_texture_cube_map,GL_ARB_texture_cube_map_array,GL_ARB_texture_env_add,GL_ARB_texture_filter_anisotropic,GL_ARB_texture_filter_minmax,GL_ARB_texture_float,GL_ARB_texture_mirror_clamp_to_edge,GL_ARB_texture_mirrored_repeat,GL_ARB_texture_multisample,GL_ARB_texture_non_power_of_two,GL_ARB_texture_rg,GL_ARB_texture_storage,GL_ARB_texture_swizzle,GL_ARB_texture_view,GL_ARB_timer_query,GL_ARB_transpose_matrix,GL_ARB_uniform_buffer_object,GL_ARB_vertex_array_bgra,GL_ARB_vertex_array_object,GL_ARB_vertex_attrib_binding,GL_ARB_vertex_buffer_object,GL_ARB_vertex_program,GL_ARB_vertex_shader,GL_EXT_draw_instanced,GL_EXT_fog_coord,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object,GL_EXT_framebuffer_sRGB,GL_EXT_texture_compression_s3tc,GL_EXT_texture_filter_anisotropic,GL_EXT_texture_mirror_clamp,GL_KHR_texture_compression_astc_hdr,GL_KHR_texture_compression_astc_ldr,GL_OES_compressed_paletted_texture,GL_OES_fixed_point' c --header-only
22 *
23 * Online:
24 * http://glad.sh/#api=gl%3Acore%3D4.3&generator=c&options=HEADER_ONLY
25 *
26 */
27
28#ifndef GLAD_GL_H_
29#define GLAD_GL_H_
30
31#ifdef __clang__
32#pragma clang diagnostic push
33#pragma clang diagnostic ignored "-Wreserved-id-macro"
34#endif
35#ifdef __gl_h_
36 #error OpenGL (gl.h) header already included (API: gl), remove previous include!
37#endif
38#define __gl_h_ 1
39#ifdef __gl3_h_
40 #error OpenGL (gl3.h) header already included (API: gl), remove previous include!
41#endif
42#define __gl3_h_ 1
43#ifdef __glext_h_
44 #error OpenGL (glext.h) header already included (API: gl), remove previous include!
45#endif
46#define __glext_h_ 1
47#ifdef __gl3ext_h_
48 #error OpenGL (gl3ext.h) header already included (API: gl), remove previous include!
49#endif
50#define __gl3ext_h_ 1
51#ifdef __clang__
52#pragma clang diagnostic pop
53#endif
54
55#define GLAD_GL
56#define GLAD_OPTION_GL_HEADER_ONLY
57
58#ifdef __cplusplus
59extern "C" {
60#endif
61
62#ifndef GLAD_PLATFORM_H_
63#define GLAD_PLATFORM_H_
64
65#ifndef GLAD_PLATFORM_WIN32
66 #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__)
67 #define GLAD_PLATFORM_WIN32 1
68 #else
69 #define GLAD_PLATFORM_WIN32 0
70 #endif
71#endif
72
73#ifndef GLAD_PLATFORM_APPLE
74 #ifdef __APPLE__
75 #define GLAD_PLATFORM_APPLE 1
76 #else
77 #define GLAD_PLATFORM_APPLE 0
78 #endif
79#endif
80
81#ifndef GLAD_PLATFORM_EMSCRIPTEN
82 #ifdef __EMSCRIPTEN__
83 #define GLAD_PLATFORM_EMSCRIPTEN 1
84 #else
85 #define GLAD_PLATFORM_EMSCRIPTEN 0
86 #endif
87#endif
88
89#ifndef GLAD_PLATFORM_UWP
90 #if defined(_MSC_VER) && !defined(GLAD_INTERNAL_HAVE_WINAPIFAMILY)
91 #ifdef __has_include
92 #if __has_include(<winapifamily.h>)
93 #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1
94 #endif
95 #elif _MSC_VER >= 1700 && !_USING_V110_SDK71_
96 #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1
97 #endif
98 #endif
99
100 #ifdef GLAD_INTERNAL_HAVE_WINAPIFAMILY
101 #include <winapifamily.h>
102 #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
103 #define GLAD_PLATFORM_UWP 1
104 #endif
105 #endif
106
107 #ifndef GLAD_PLATFORM_UWP
108 #define GLAD_PLATFORM_UWP 0
109 #endif
110#endif
111
112#ifdef __GNUC__
113 #define GLAD_GNUC_EXTENSION __extension__
114#else
115 #define GLAD_GNUC_EXTENSION
116#endif
117
118#ifndef GLAD_API_CALL
119 #if defined(GLAD_API_CALL_EXPORT)
120 #if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__)
121 #if defined(GLAD_API_CALL_EXPORT_BUILD)
122 #if defined(__GNUC__)
123 #define GLAD_API_CALL __attribute__ ((dllexport)) extern
124 #else
125 #define GLAD_API_CALL __declspec(dllexport) extern
126 #endif
127 #else
128 #if defined(__GNUC__)
129 #define GLAD_API_CALL __attribute__ ((dllimport)) extern
130 #else
131 #define GLAD_API_CALL __declspec(dllimport) extern
132 #endif
133 #endif
134 #elif defined(__GNUC__) && defined(GLAD_API_CALL_EXPORT_BUILD)
135 #define GLAD_API_CALL __attribute__ ((visibility ("default"))) extern
136 #else
137 #define GLAD_API_CALL extern
138 #endif
139 #else
140 #define GLAD_API_CALL extern
141 #endif
142#endif
143
144#ifdef APIENTRY
145 #define GLAD_API_PTR APIENTRY
146#elif GLAD_PLATFORM_WIN32
147 #define GLAD_API_PTR __stdcall
148#else
149 #define GLAD_API_PTR
150#endif
151
152#ifndef GLAPI
153#define GLAPI GLAD_API_CALL
154#endif
155
156#ifndef GLAPIENTRY
157#define GLAPIENTRY GLAD_API_PTR
158#endif
159
160#define GLAD_MAKE_VERSION(major, minor) (major * 10000 + minor)
161#define GLAD_VERSION_MAJOR(version) (version / 10000)
162#define GLAD_VERSION_MINOR(version) (version % 10000)
163
164#define GLAD_GENERATOR_VERSION "2.0.0-beta"
165
166typedef void (*GLADapiproc)(void);
167
168typedef GLADapiproc (*GLADloadfunc)(const char *name);
169typedef GLADapiproc (*GLADuserptrloadfunc)(void *userptr, const char *name);
170
171typedef void (*GLADprecallback)(const char *name, GLADapiproc apiproc, int len_args, ...);
172typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apiproc, int len_args, ...);
173
174#endif /* GLAD_PLATFORM_H_ */
175
176#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9
177#define GL_ACTIVE_ATTRIBUTES 0x8B89
178#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
179#define GL_ACTIVE_PROGRAM 0x8259
180#define GL_ACTIVE_RESOURCES 0x92F5
181#define GL_ACTIVE_SUBROUTINES 0x8DE5
182#define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48
183#define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6
184#define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47
185#define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49
186#define GL_ACTIVE_TEXTURE 0x84E0
187#define GL_ACTIVE_TEXTURE_ARB 0x84E0
188#define GL_ACTIVE_UNIFORMS 0x8B86
189#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36
190#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35
191#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
192#define GL_ACTIVE_VARIABLES 0x9305
193#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
194#define GL_ALL_BARRIER_BITS 0xFFFFFFFF
195#define GL_ALL_SHADER_BITS 0xFFFFFFFF
196#define GL_ALPHA 0x1906
197#define GL_ALPHA16F_ARB 0x881C
198#define GL_ALPHA32F_ARB 0x8816
199#define GL_ALREADY_SIGNALED 0x911A
200#define GL_ALWAYS 0x0207
201#define GL_AND 0x1501
202#define GL_AND_INVERTED 0x1504
203#define GL_AND_REVERSE 0x1502
204#define GL_ANY_SAMPLES_PASSED 0x8C2F
205#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A
206#define GL_ARRAY_BUFFER 0x8892
207#define GL_ARRAY_BUFFER_ARB 0x8892
208#define GL_ARRAY_BUFFER_BINDING 0x8894
209#define GL_ARRAY_BUFFER_BINDING_ARB 0x8894
210#define GL_ARRAY_SIZE 0x92FB
211#define GL_ARRAY_STRIDE 0x92FE
212#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000
213#define GL_ATOMIC_COUNTER_BUFFER 0x92C0
214#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5
215#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6
216#define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1
217#define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4
218#define GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301
219#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER 0x90ED
220#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB
221#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA
222#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8
223#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9
224#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7
225#define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3
226#define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2
227#define GL_ATTACHED_SHADERS 0x8B85
228#define GL_AUTO_GENERATE_MIPMAP 0x8295
229#define GL_BACK 0x0405
230#define GL_BACK_LEFT 0x0402
231#define GL_BACK_RIGHT 0x0403
232#define GL_BGR 0x80E0
233#define GL_BGRA 0x80E1
234#define GL_BGRA_INTEGER 0x8D9B
235#define GL_BGR_INTEGER 0x8D9A
236#define GL_BLEND 0x0BE2
237#define GL_BLEND_COLOR 0x8005
238#define GL_BLEND_DST 0x0BE0
239#define GL_BLEND_DST_ALPHA 0x80CA
240#define GL_BLEND_DST_RGB 0x80C8
241#define GL_BLEND_EQUATION 0x8009
242#define GL_BLEND_EQUATION_ALPHA 0x883D
243#define GL_BLEND_EQUATION_RGB 0x8009
244#define GL_BLEND_SRC 0x0BE1
245#define GL_BLEND_SRC_ALPHA 0x80CB
246#define GL_BLEND_SRC_RGB 0x80C9
247#define GL_BLOCK_INDEX 0x92FD
248#define GL_BLUE 0x1905
249#define GL_BLUE_INTEGER 0x8D96
250#define GL_BOOL 0x8B56
251#define GL_BOOL_ARB 0x8B56
252#define GL_BOOL_VEC2 0x8B57
253#define GL_BOOL_VEC2_ARB 0x8B57
254#define GL_BOOL_VEC3 0x8B58
255#define GL_BOOL_VEC3_ARB 0x8B58
256#define GL_BOOL_VEC4 0x8B59
257#define GL_BOOL_VEC4_ARB 0x8B59
258#define GL_BUFFER 0x82E0
259#define GL_BUFFER_ACCESS 0x88BB
260#define GL_BUFFER_ACCESS_ARB 0x88BB
261#define GL_BUFFER_ACCESS_FLAGS 0x911F
262#define GL_BUFFER_BINDING 0x9302
263#define GL_BUFFER_DATA_SIZE 0x9303
264#define GL_BUFFER_IMMUTABLE_STORAGE 0x821F
265#define GL_BUFFER_MAPPED 0x88BC
266#define GL_BUFFER_MAPPED_ARB 0x88BC
267#define GL_BUFFER_MAP_LENGTH 0x9120
268#define GL_BUFFER_MAP_OFFSET 0x9121
269#define GL_BUFFER_MAP_POINTER 0x88BD
270#define GL_BUFFER_MAP_POINTER_ARB 0x88BD
271#define GL_BUFFER_SIZE 0x8764
272#define GL_BUFFER_SIZE_ARB 0x8764
273#define GL_BUFFER_STORAGE_FLAGS 0x8220
274#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200
275#define GL_BUFFER_USAGE 0x8765
276#define GL_BUFFER_USAGE_ARB 0x8765
277#define GL_BUFFER_VARIABLE 0x92E5
278#define GL_BYTE 0x1400
279#define GL_CAVEAT_SUPPORT 0x82B8
280#define GL_CCW 0x0901
281#define GL_CLAMP_FRAGMENT_COLOR_ARB 0x891B
282#define GL_CLAMP_READ_COLOR 0x891C
283#define GL_CLAMP_READ_COLOR_ARB 0x891C
284#define GL_CLAMP_TO_BORDER 0x812D
285#define GL_CLAMP_TO_BORDER_ARB 0x812D
286#define GL_CLAMP_TO_EDGE 0x812F
287#define GL_CLAMP_VERTEX_COLOR_ARB 0x891A
288#define GL_CLEAR 0x1500
289#define GL_CLEAR_BUFFER 0x82B4
290#define GL_CLEAR_TEXTURE 0x9365
291#define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1
292#define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT 0x00004000
293#define GL_CLIENT_STORAGE_BIT 0x0200
294#define GL_CLIPPING_INPUT_PRIMITIVES 0x82F6
295#define GL_CLIPPING_INPUT_PRIMITIVES_ARB 0x82F6
296#define GL_CLIPPING_OUTPUT_PRIMITIVES 0x82F7
297#define GL_CLIPPING_OUTPUT_PRIMITIVES_ARB 0x82F7
298#define GL_CLIP_DISTANCE0 0x3000
299#define GL_CLIP_DISTANCE1 0x3001
300#define GL_CLIP_DISTANCE2 0x3002
301#define GL_CLIP_DISTANCE3 0x3003
302#define GL_CLIP_DISTANCE4 0x3004
303#define GL_CLIP_DISTANCE5 0x3005
304#define GL_CLIP_DISTANCE6 0x3006
305#define GL_CLIP_DISTANCE7 0x3007
306#define GL_COLOR 0x1800
307#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898
308#define GL_COLOR_ATTACHMENT0 0x8CE0
309#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0
310#define GL_COLOR_ATTACHMENT1 0x8CE1
311#define GL_COLOR_ATTACHMENT10 0x8CEA
312#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA
313#define GL_COLOR_ATTACHMENT11 0x8CEB
314#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB
315#define GL_COLOR_ATTACHMENT12 0x8CEC
316#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC
317#define GL_COLOR_ATTACHMENT13 0x8CED
318#define GL_COLOR_ATTACHMENT13_EXT 0x8CED
319#define GL_COLOR_ATTACHMENT14 0x8CEE
320#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE
321#define GL_COLOR_ATTACHMENT15 0x8CEF
322#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF
323#define GL_COLOR_ATTACHMENT16 0x8CF0
324#define GL_COLOR_ATTACHMENT17 0x8CF1
325#define GL_COLOR_ATTACHMENT18 0x8CF2
326#define GL_COLOR_ATTACHMENT19 0x8CF3
327#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1
328#define GL_COLOR_ATTACHMENT2 0x8CE2
329#define GL_COLOR_ATTACHMENT20 0x8CF4
330#define GL_COLOR_ATTACHMENT21 0x8CF5
331#define GL_COLOR_ATTACHMENT22 0x8CF6
332#define GL_COLOR_ATTACHMENT23 0x8CF7
333#define GL_COLOR_ATTACHMENT24 0x8CF8
334#define GL_COLOR_ATTACHMENT25 0x8CF9
335#define GL_COLOR_ATTACHMENT26 0x8CFA
336#define GL_COLOR_ATTACHMENT27 0x8CFB
337#define GL_COLOR_ATTACHMENT28 0x8CFC
338#define GL_COLOR_ATTACHMENT29 0x8CFD
339#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2
340#define GL_COLOR_ATTACHMENT3 0x8CE3
341#define GL_COLOR_ATTACHMENT30 0x8CFE
342#define GL_COLOR_ATTACHMENT31 0x8CFF
343#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3
344#define GL_COLOR_ATTACHMENT4 0x8CE4
345#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4
346#define GL_COLOR_ATTACHMENT5 0x8CE5
347#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5
348#define GL_COLOR_ATTACHMENT6 0x8CE6
349#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6
350#define GL_COLOR_ATTACHMENT7 0x8CE7
351#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7
352#define GL_COLOR_ATTACHMENT8 0x8CE8
353#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8
354#define GL_COLOR_ATTACHMENT9 0x8CE9
355#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9
356#define GL_COLOR_BUFFER_BIT 0x00004000
357#define GL_COLOR_CLEAR_VALUE 0x0C22
358#define GL_COLOR_COMPONENTS 0x8283
359#define GL_COLOR_ENCODING 0x8296
360#define GL_COLOR_LOGIC_OP 0x0BF2
361#define GL_COLOR_RENDERABLE 0x8286
362#define GL_COLOR_SUM_ARB 0x8458
363#define GL_COLOR_WRITEMASK 0x0C23
364#define GL_COMMAND_BARRIER_BIT 0x00000040
365#define GL_COMPARE_REF_TO_TEXTURE 0x884E
366#define GL_COMPATIBLE_SUBROUTINES 0x8E4B
367#define GL_COMPILE_STATUS 0x8B81
368#define GL_COMPRESSED_ALPHA_ARB 0x84E9
369#define GL_COMPRESSED_INTENSITY_ARB 0x84EC
370#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB
371#define GL_COMPRESSED_LUMINANCE_ARB 0x84EA
372#define GL_COMPRESSED_R11_EAC 0x9270
373#define GL_COMPRESSED_RED 0x8225
374#define GL_COMPRESSED_RED_RGTC1 0x8DBB
375#define GL_COMPRESSED_RG 0x8226
376#define GL_COMPRESSED_RG11_EAC 0x9272
377#define GL_COMPRESSED_RGB 0x84ED
378#define GL_COMPRESSED_RGB8_ETC2 0x9274
379#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276
380#define GL_COMPRESSED_RGBA 0x84EE
381#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
382#define GL_COMPRESSED_RGBA_ARB 0x84EE
383#define GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB
384#define GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8
385#define GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9
386#define GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA
387#define GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC
388#define GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD
389#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0
390#define GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1
391#define GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2
392#define GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3
393#define GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4
394#define GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5
395#define GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6
396#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7
397#define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C
398#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
399#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
400#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
401#define GL_COMPRESSED_RGB_ARB 0x84ED
402#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E
403#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F
404#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
405#define GL_COMPRESSED_RG_RGTC2 0x8DBD
406#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271
407#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC
408#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273
409#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE
410#define GL_COMPRESSED_SRGB 0x8C48
411#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB
412#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8
413#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9
414#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA
415#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC
416#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD
417#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0
418#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1
419#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2
420#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3
421#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4
422#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5
423#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6
424#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7
425#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279
426#define GL_COMPRESSED_SRGB8_ETC2 0x9275
427#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277
428#define GL_COMPRESSED_SRGB_ALPHA 0x8C49
429#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D
430#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
431#define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3
432#define GL_COMPUTE_SHADER 0x91B9
433#define GL_COMPUTE_SHADER_BIT 0x00000020
434#define GL_COMPUTE_SHADER_INVOCATIONS 0x82F5
435#define GL_COMPUTE_SHADER_INVOCATIONS_ARB 0x82F5
436#define GL_COMPUTE_SUBROUTINE 0x92ED
437#define GL_COMPUTE_SUBROUTINE_UNIFORM 0x92F3
438#define GL_COMPUTE_TEXTURE 0x82A0
439#define GL_COMPUTE_WORK_GROUP_SIZE 0x8267
440#define GL_CONDITION_SATISFIED 0x911C
441#define GL_CONSTANT_ALPHA 0x8003
442#define GL_CONSTANT_COLOR 0x8001
443#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
444#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001
445#define GL_CONTEXT_FLAGS 0x821E
446#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
447#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001
448#define GL_CONTEXT_PROFILE_MASK 0x9126
449#define GL_COPY 0x1503
450#define GL_COPY_INVERTED 0x150C
451#define GL_COPY_READ_BUFFER 0x8F36
452#define GL_COPY_READ_BUFFER_BINDING 0x8F36
453#define GL_COPY_WRITE_BUFFER 0x8F37
454#define GL_COPY_WRITE_BUFFER_BINDING 0x8F37
455#define GL_CULL_FACE 0x0B44
456#define GL_CULL_FACE_MODE 0x0B45
457#define GL_CURRENT_FOG_COORDINATE_EXT 0x8453
458#define GL_CURRENT_MATRIX_ARB 0x8641
459#define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640
460#define GL_CURRENT_PROGRAM 0x8B8D
461#define GL_CURRENT_QUERY 0x8865
462#define GL_CURRENT_QUERY_ARB 0x8865
463#define GL_CURRENT_VERTEX_ATTRIB 0x8626
464#define GL_CURRENT_VERTEX_ATTRIB_ARB 0x8626
465#define GL_CW 0x0900
466#define GL_DEBUG_CALLBACK_FUNCTION 0x8244
467#define GL_DEBUG_CALLBACK_FUNCTION_ARB 0x8244
468#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245
469#define GL_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245
470#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D
471#define GL_DEBUG_LOGGED_MESSAGES 0x9145
472#define GL_DEBUG_LOGGED_MESSAGES_ARB 0x9145
473#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243
474#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243
475#define GL_DEBUG_OUTPUT 0x92E0
476#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
477#define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242
478#define GL_DEBUG_SEVERITY_HIGH 0x9146
479#define GL_DEBUG_SEVERITY_HIGH_ARB 0x9146
480#define GL_DEBUG_SEVERITY_LOW 0x9148
481#define GL_DEBUG_SEVERITY_LOW_ARB 0x9148
482#define GL_DEBUG_SEVERITY_MEDIUM 0x9147
483#define GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147
484#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B
485#define GL_DEBUG_SOURCE_API 0x8246
486#define GL_DEBUG_SOURCE_API_ARB 0x8246
487#define GL_DEBUG_SOURCE_APPLICATION 0x824A
488#define GL_DEBUG_SOURCE_APPLICATION_ARB 0x824A
489#define GL_DEBUG_SOURCE_OTHER 0x824B
490#define GL_DEBUG_SOURCE_OTHER_ARB 0x824B
491#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248
492#define GL_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248
493#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249
494#define GL_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249
495#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247
496#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247
497#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D
498#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D
499#define GL_DEBUG_TYPE_ERROR 0x824C
500#define GL_DEBUG_TYPE_ERROR_ARB 0x824C
501#define GL_DEBUG_TYPE_MARKER 0x8268
502#define GL_DEBUG_TYPE_OTHER 0x8251
503#define GL_DEBUG_TYPE_OTHER_ARB 0x8251
504#define GL_DEBUG_TYPE_PERFORMANCE 0x8250
505#define GL_DEBUG_TYPE_PERFORMANCE_ARB 0x8250
506#define GL_DEBUG_TYPE_POP_GROUP 0x826A
507#define GL_DEBUG_TYPE_PORTABILITY 0x824F
508#define GL_DEBUG_TYPE_PORTABILITY_ARB 0x824F
509#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269
510#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E
511#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E
512#define GL_DECR 0x1E03
513#define GL_DECR_WRAP 0x8508
514#define GL_DELETE_STATUS 0x8B80
515#define GL_DEPTH 0x1801
516#define GL_DEPTH24_STENCIL8 0x88F0
517#define GL_DEPTH32F_STENCIL8 0x8CAD
518#define GL_DEPTH_ATTACHMENT 0x8D00
519#define GL_DEPTH_ATTACHMENT_EXT 0x8D00
520#define GL_DEPTH_BUFFER_BIT 0x00000100
521#define GL_DEPTH_CLAMP 0x864F
522#define GL_DEPTH_CLEAR_VALUE 0x0B73
523#define GL_DEPTH_COMPONENT 0x1902
524#define GL_DEPTH_COMPONENT16 0x81A5
525#define GL_DEPTH_COMPONENT16_ARB 0x81A5
526#define GL_DEPTH_COMPONENT24 0x81A6
527#define GL_DEPTH_COMPONENT24_ARB 0x81A6
528#define GL_DEPTH_COMPONENT32 0x81A7
529#define GL_DEPTH_COMPONENT32F 0x8CAC
530#define GL_DEPTH_COMPONENT32_ARB 0x81A7
531#define GL_DEPTH_COMPONENTS 0x8284
532#define GL_DEPTH_FUNC 0x0B74
533#define GL_DEPTH_RANGE 0x0B70
534#define GL_DEPTH_RENDERABLE 0x8287
535#define GL_DEPTH_STENCIL 0x84F9
536#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
537#define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA
538#define GL_DEPTH_TEST 0x0B71
539#define GL_DEPTH_TEXTURE_MODE_ARB 0x884B
540#define GL_DEPTH_WRITEMASK 0x0B72
541#define GL_DISPATCH_INDIRECT_BUFFER 0x90EE
542#define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF
543#define GL_DITHER 0x0BD0
544#define GL_DONT_CARE 0x1100
545#define GL_DOUBLE 0x140A
546#define GL_DOUBLEBUFFER 0x0C32
547#define GL_DOUBLE_MAT2 0x8F46
548#define GL_DOUBLE_MAT2x3 0x8F49
549#define GL_DOUBLE_MAT2x4 0x8F4A
550#define GL_DOUBLE_MAT3 0x8F47
551#define GL_DOUBLE_MAT3x2 0x8F4B
552#define GL_DOUBLE_MAT3x4 0x8F4C
553#define GL_DOUBLE_MAT4 0x8F48
554#define GL_DOUBLE_MAT4x2 0x8F4D
555#define GL_DOUBLE_MAT4x3 0x8F4E
556#define GL_DOUBLE_VEC2 0x8FFC
557#define GL_DOUBLE_VEC3 0x8FFD
558#define GL_DOUBLE_VEC4 0x8FFE
559#define GL_DRAW_BUFFER 0x0C01
560#define GL_DRAW_BUFFER0 0x8825
561#define GL_DRAW_BUFFER0_ARB 0x8825
562#define GL_DRAW_BUFFER1 0x8826
563#define GL_DRAW_BUFFER10 0x882F
564#define GL_DRAW_BUFFER10_ARB 0x882F
565#define GL_DRAW_BUFFER11 0x8830
566#define GL_DRAW_BUFFER11_ARB 0x8830
567#define GL_DRAW_BUFFER12 0x8831
568#define GL_DRAW_BUFFER12_ARB 0x8831
569#define GL_DRAW_BUFFER13 0x8832
570#define GL_DRAW_BUFFER13_ARB 0x8832
571#define GL_DRAW_BUFFER14 0x8833
572#define GL_DRAW_BUFFER14_ARB 0x8833
573#define GL_DRAW_BUFFER15 0x8834
574#define GL_DRAW_BUFFER15_ARB 0x8834
575#define GL_DRAW_BUFFER1_ARB 0x8826
576#define GL_DRAW_BUFFER2 0x8827
577#define GL_DRAW_BUFFER2_ARB 0x8827
578#define GL_DRAW_BUFFER3 0x8828
579#define GL_DRAW_BUFFER3_ARB 0x8828
580#define GL_DRAW_BUFFER4 0x8829
581#define GL_DRAW_BUFFER4_ARB 0x8829
582#define GL_DRAW_BUFFER5 0x882A
583#define GL_DRAW_BUFFER5_ARB 0x882A
584#define GL_DRAW_BUFFER6 0x882B
585#define GL_DRAW_BUFFER6_ARB 0x882B
586#define GL_DRAW_BUFFER7 0x882C
587#define GL_DRAW_BUFFER7_ARB 0x882C
588#define GL_DRAW_BUFFER8 0x882D
589#define GL_DRAW_BUFFER8_ARB 0x882D
590#define GL_DRAW_BUFFER9 0x882E
591#define GL_DRAW_BUFFER9_ARB 0x882E
592#define GL_DRAW_FRAMEBUFFER 0x8CA9
593#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6
594#define GL_DRAW_FRAMEBUFFER_BINDING_EXT 0x8CA6
595#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9
596#define GL_DRAW_INDIRECT_BUFFER 0x8F3F
597#define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43
598#define GL_DST_ALPHA 0x0304
599#define GL_DST_COLOR 0x0306
600#define GL_DYNAMIC_COPY 0x88EA
601#define GL_DYNAMIC_COPY_ARB 0x88EA
602#define GL_DYNAMIC_DRAW 0x88E8
603#define GL_DYNAMIC_DRAW_ARB 0x88E8
604#define GL_DYNAMIC_READ 0x88E9
605#define GL_DYNAMIC_READ_ARB 0x88E9
606#define GL_DYNAMIC_STORAGE_BIT 0x0100
607#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B
608#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002
609#define GL_ELEMENT_ARRAY_BUFFER 0x8893
610#define GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893
611#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
612#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895
613#define GL_EQUAL 0x0202
614#define GL_EQUIV 0x1509
615#define GL_EXTENSIONS 0x1F03
616#define GL_FALSE 0
617#define GL_FASTEST 0x1101
618#define GL_FILL 0x1B02
619#define GL_FILTER 0x829A
620#define GL_FIRST_VERTEX_CONVENTION 0x8E4D
621#define GL_FIXED 0x140C
622#define GL_FIXED_OES 0x140C
623#define GL_FIXED_ONLY 0x891D
624#define GL_FIXED_ONLY_ARB 0x891D
625#define GL_FLOAT 0x1406
626#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD
627#define GL_FLOAT_MAT2 0x8B5A
628#define GL_FLOAT_MAT2_ARB 0x8B5A
629#define GL_FLOAT_MAT2x3 0x8B65
630#define GL_FLOAT_MAT2x4 0x8B66
631#define GL_FLOAT_MAT3 0x8B5B
632#define GL_FLOAT_MAT3_ARB 0x8B5B
633#define GL_FLOAT_MAT3x2 0x8B67
634#define GL_FLOAT_MAT3x4 0x8B68
635#define GL_FLOAT_MAT4 0x8B5C
636#define GL_FLOAT_MAT4_ARB 0x8B5C
637#define GL_FLOAT_MAT4x2 0x8B69
638#define GL_FLOAT_MAT4x3 0x8B6A
639#define GL_FLOAT_VEC2 0x8B50
640#define GL_FLOAT_VEC2_ARB 0x8B50
641#define GL_FLOAT_VEC3 0x8B51
642#define GL_FLOAT_VEC3_ARB 0x8B51
643#define GL_FLOAT_VEC4 0x8B52
644#define GL_FLOAT_VEC4_ARB 0x8B52
645#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D
646#define GL_FOG_COORDINATE_ARRAY_EXT 0x8457
647#define GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456
648#define GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455
649#define GL_FOG_COORDINATE_ARRAY_TYPE_EXT 0x8454
650#define GL_FOG_COORDINATE_EXT 0x8451
651#define GL_FOG_COORDINATE_SOURCE_EXT 0x8450
652#define GL_FRACTIONAL_EVEN 0x8E7C
653#define GL_FRACTIONAL_ODD 0x8E7B
654#define GL_FRAGMENT_DEPTH_EXT 0x8452
655#define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D
656#define GL_FRAGMENT_PROGRAM_ARB 0x8804
657#define GL_FRAGMENT_SHADER 0x8B30
658#define GL_FRAGMENT_SHADER_ARB 0x8B30
659#define GL_FRAGMENT_SHADER_BIT 0x00000002
660#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B
661#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B
662#define GL_FRAGMENT_SHADER_INVOCATIONS 0x82F4
663#define GL_FRAGMENT_SHADER_INVOCATIONS_ARB 0x82F4
664#define GL_FRAGMENT_SUBROUTINE 0x92EC
665#define GL_FRAGMENT_SUBROUTINE_UNIFORM 0x92F2
666#define GL_FRAGMENT_TEXTURE 0x829F
667#define GL_FRAMEBUFFER 0x8D40
668#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215
669#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214
670#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210
671#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211
672#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216
673#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213
674#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7
675#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB 0x8DA7
676#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
677#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1
678#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
679#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0
680#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212
681#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217
682#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4
683#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
684#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3
685#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4
686#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
687#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2
688#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400
689#define GL_FRAMEBUFFER_BINDING 0x8CA6
690#define GL_FRAMEBUFFER_BINDING_EXT 0x8CA6
691#define GL_FRAMEBUFFER_BLEND 0x828B
692#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
693#define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5
694#define GL_FRAMEBUFFER_DEFAULT 0x8218
695#define GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 0x9314
696#define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311
697#define GL_FRAMEBUFFER_DEFAULT_LAYERS 0x9312
698#define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313
699#define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310
700#define GL_FRAMEBUFFER_EXT 0x8D40
701#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
702#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6
703#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9
704#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB
705#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB
706#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA
707#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB 0x8DA9
708#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8
709#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB 0x8DA8
710#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
711#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7
712#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56
713#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56
714#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC
715#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC
716#define GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB 0x9342
717#define GL_FRAMEBUFFER_RENDERABLE 0x8289
718#define GL_FRAMEBUFFER_RENDERABLE_LAYERED 0x828A
719#define GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB 0x9343
720#define GL_FRAMEBUFFER_SRGB 0x8DB9
721#define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x8DBA
722#define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9
723#define GL_FRAMEBUFFER_UNDEFINED 0x8219
724#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
725#define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD
726#define GL_FRONT 0x0404
727#define GL_FRONT_AND_BACK 0x0408
728#define GL_FRONT_FACE 0x0B46
729#define GL_FRONT_LEFT 0x0400
730#define GL_FRONT_RIGHT 0x0401
731#define GL_FULL_SUPPORT 0x82B7
732#define GL_FUNC_ADD 0x8006
733#define GL_FUNC_REVERSE_SUBTRACT 0x800B
734#define GL_FUNC_SUBTRACT 0x800A
735#define GL_GEOMETRY_INPUT_TYPE 0x8917
736#define GL_GEOMETRY_INPUT_TYPE_ARB 0x8DDB
737#define GL_GEOMETRY_OUTPUT_TYPE 0x8918
738#define GL_GEOMETRY_OUTPUT_TYPE_ARB 0x8DDC
739#define GL_GEOMETRY_SHADER 0x8DD9
740#define GL_GEOMETRY_SHADER_ARB 0x8DD9
741#define GL_GEOMETRY_SHADER_BIT 0x00000004
742#define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F
743#define GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED 0x82F3
744#define GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB 0x82F3
745#define GL_GEOMETRY_SUBROUTINE 0x92EB
746#define GL_GEOMETRY_SUBROUTINE_UNIFORM 0x92F1
747#define GL_GEOMETRY_TEXTURE 0x829E
748#define GL_GEOMETRY_VERTICES_OUT 0x8916
749#define GL_GEOMETRY_VERTICES_OUT_ARB 0x8DDA
750#define GL_GEQUAL 0x0206
751#define GL_GET_TEXTURE_IMAGE_FORMAT 0x8291
752#define GL_GET_TEXTURE_IMAGE_TYPE 0x8292
753#define GL_GREATER 0x0204
754#define GL_GREEN 0x1904
755#define GL_GREEN_INTEGER 0x8D95
756#define GL_HALF_FLOAT 0x140B
757#define GL_HALF_FLOAT_ARB 0x140B
758#define GL_HIGH_FLOAT 0x8DF2
759#define GL_HIGH_INT 0x8DF5
760#define GL_IMAGE_1D 0x904C
761#define GL_IMAGE_1D_ARRAY 0x9052
762#define GL_IMAGE_2D 0x904D
763#define GL_IMAGE_2D_ARRAY 0x9053
764#define GL_IMAGE_2D_MULTISAMPLE 0x9055
765#define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056
766#define GL_IMAGE_2D_RECT 0x904F
767#define GL_IMAGE_3D 0x904E
768#define GL_IMAGE_BINDING_ACCESS 0x8F3E
769#define GL_IMAGE_BINDING_FORMAT 0x906E
770#define GL_IMAGE_BINDING_LAYER 0x8F3D
771#define GL_IMAGE_BINDING_LAYERED 0x8F3C
772#define GL_IMAGE_BINDING_LEVEL 0x8F3B
773#define GL_IMAGE_BINDING_NAME 0x8F3A
774#define GL_IMAGE_BUFFER 0x9051
775#define GL_IMAGE_CLASS_10_10_10_2 0x82C3
776#define GL_IMAGE_CLASS_11_11_10 0x82C2
777#define GL_IMAGE_CLASS_1_X_16 0x82BE
778#define GL_IMAGE_CLASS_1_X_32 0x82BB
779#define GL_IMAGE_CLASS_1_X_8 0x82C1
780#define GL_IMAGE_CLASS_2_X_16 0x82BD
781#define GL_IMAGE_CLASS_2_X_32 0x82BA
782#define GL_IMAGE_CLASS_2_X_8 0x82C0
783#define GL_IMAGE_CLASS_4_X_16 0x82BC
784#define GL_IMAGE_CLASS_4_X_32 0x82B9
785#define GL_IMAGE_CLASS_4_X_8 0x82BF
786#define GL_IMAGE_COMPATIBILITY_CLASS 0x82A8
787#define GL_IMAGE_CUBE 0x9050
788#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054
789#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9
790#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8
791#define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7
792#define GL_IMAGE_PIXEL_FORMAT 0x82A9
793#define GL_IMAGE_PIXEL_TYPE 0x82AA
794#define GL_IMAGE_TEXEL_SIZE 0x82A7
795#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
796#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
797#define GL_INCR 0x1E02
798#define GL_INCR_WRAP 0x8507
799#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899
800#define GL_INFO_LOG_LENGTH 0x8B84
801#define GL_INT 0x1404
802#define GL_INT64_ARB 0x140E
803#define GL_INT64_VEC2_ARB 0x8FE9
804#define GL_INT64_VEC3_ARB 0x8FEA
805#define GL_INT64_VEC4_ARB 0x8FEB
806#define GL_INTENSITY16F_ARB 0x881D
807#define GL_INTENSITY32F_ARB 0x8817
808#define GL_INTERLEAVED_ATTRIBS 0x8C8C
809#define GL_INTERNALFORMAT_ALPHA_SIZE 0x8274
810#define GL_INTERNALFORMAT_ALPHA_TYPE 0x827B
811#define GL_INTERNALFORMAT_BLUE_SIZE 0x8273
812#define GL_INTERNALFORMAT_BLUE_TYPE 0x827A
813#define GL_INTERNALFORMAT_DEPTH_SIZE 0x8275
814#define GL_INTERNALFORMAT_DEPTH_TYPE 0x827C
815#define GL_INTERNALFORMAT_GREEN_SIZE 0x8272
816#define GL_INTERNALFORMAT_GREEN_TYPE 0x8279
817#define GL_INTERNALFORMAT_PREFERRED 0x8270
818#define GL_INTERNALFORMAT_RED_SIZE 0x8271
819#define GL_INTERNALFORMAT_RED_TYPE 0x8278
820#define GL_INTERNALFORMAT_SHARED_SIZE 0x8277
821#define GL_INTERNALFORMAT_STENCIL_SIZE 0x8276
822#define GL_INTERNALFORMAT_STENCIL_TYPE 0x827D
823#define GL_INTERNALFORMAT_SUPPORTED 0x826F
824#define GL_INT_2_10_10_10_REV 0x8D9F
825#define GL_INT_IMAGE_1D 0x9057
826#define GL_INT_IMAGE_1D_ARRAY 0x905D
827#define GL_INT_IMAGE_2D 0x9058
828#define GL_INT_IMAGE_2D_ARRAY 0x905E
829#define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060
830#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061
831#define GL_INT_IMAGE_2D_RECT 0x905A
832#define GL_INT_IMAGE_3D 0x9059
833#define GL_INT_IMAGE_BUFFER 0x905C
834#define GL_INT_IMAGE_CUBE 0x905B
835#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F
836#define GL_INT_SAMPLER_1D 0x8DC9
837#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE
838#define GL_INT_SAMPLER_2D 0x8DCA
839#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF
840#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109
841#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C
842#define GL_INT_SAMPLER_2D_RECT 0x8DCD
843#define GL_INT_SAMPLER_3D 0x8DCB
844#define GL_INT_SAMPLER_BUFFER 0x8DD0
845#define GL_INT_SAMPLER_CUBE 0x8DCC
846#define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E
847#define GL_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900E
848#define GL_INT_VEC2 0x8B53
849#define GL_INT_VEC2_ARB 0x8B53
850#define GL_INT_VEC3 0x8B54
851#define GL_INT_VEC3_ARB 0x8B54
852#define GL_INT_VEC4 0x8B55
853#define GL_INT_VEC4_ARB 0x8B55
854#define GL_INVALID_ENUM 0x0500
855#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
856#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506
857#define GL_INVALID_INDEX 0xFFFFFFFF
858#define GL_INVALID_OPERATION 0x0502
859#define GL_INVALID_VALUE 0x0501
860#define GL_INVERT 0x150A
861#define GL_ISOLINES 0x8E7A
862#define GL_IS_PER_PATCH 0x92E7
863#define GL_IS_ROW_MAJOR 0x9300
864#define GL_KEEP 0x1E00
865#define GL_LAST_VERTEX_CONVENTION 0x8E4E
866#define GL_LAYER_PROVOKING_VERTEX 0x825E
867#define GL_LEFT 0x0406
868#define GL_LEQUAL 0x0203
869#define GL_LESS 0x0201
870#define GL_LINE 0x1B01
871#define GL_LINEAR 0x2601
872#define GL_LINEAR_MIPMAP_LINEAR 0x2703
873#define GL_LINEAR_MIPMAP_NEAREST 0x2701
874#define GL_LINES 0x0001
875#define GL_LINES_ADJACENCY 0x000A
876#define GL_LINES_ADJACENCY_ARB 0x000A
877#define GL_LINE_LOOP 0x0002
878#define GL_LINE_SMOOTH 0x0B20
879#define GL_LINE_SMOOTH_HINT 0x0C52
880#define GL_LINE_STRIP 0x0003
881#define GL_LINE_STRIP_ADJACENCY 0x000B
882#define GL_LINE_STRIP_ADJACENCY_ARB 0x000B
883#define GL_LINE_WIDTH 0x0B21
884#define GL_LINE_WIDTH_GRANULARITY 0x0B23
885#define GL_LINE_WIDTH_RANGE 0x0B22
886#define GL_LINK_STATUS 0x8B82
887#define GL_LOCATION 0x930E
888#define GL_LOCATION_COMPONENT 0x934A
889#define GL_LOCATION_INDEX 0x930F
890#define GL_LOGIC_OP_MODE 0x0BF0
891#define GL_LOWER_LEFT 0x8CA1
892#define GL_LOW_FLOAT 0x8DF0
893#define GL_LOW_INT 0x8DF3
894#define GL_LUMINANCE16F_ARB 0x881E
895#define GL_LUMINANCE32F_ARB 0x8818
896#define GL_LUMINANCE_ALPHA16F_ARB 0x881F
897#define GL_LUMINANCE_ALPHA32F_ARB 0x8819
898#define GL_MAJOR_VERSION 0x821B
899#define GL_MANUAL_GENERATE_MIPMAP 0x8294
900#define GL_MAP_COHERENT_BIT 0x0080
901#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010
902#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008
903#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004
904#define GL_MAP_PERSISTENT_BIT 0x0040
905#define GL_MAP_READ_BIT 0x0001
906#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020
907#define GL_MAP_WRITE_BIT 0x0002
908#define GL_MATRIX0_ARB 0x88C0
909#define GL_MATRIX10_ARB 0x88CA
910#define GL_MATRIX11_ARB 0x88CB
911#define GL_MATRIX12_ARB 0x88CC
912#define GL_MATRIX13_ARB 0x88CD
913#define GL_MATRIX14_ARB 0x88CE
914#define GL_MATRIX15_ARB 0x88CF
915#define GL_MATRIX16_ARB 0x88D0
916#define GL_MATRIX17_ARB 0x88D1
917#define GL_MATRIX18_ARB 0x88D2
918#define GL_MATRIX19_ARB 0x88D3
919#define GL_MATRIX1_ARB 0x88C1
920#define GL_MATRIX20_ARB 0x88D4
921#define GL_MATRIX21_ARB 0x88D5
922#define GL_MATRIX22_ARB 0x88D6
923#define GL_MATRIX23_ARB 0x88D7
924#define GL_MATRIX24_ARB 0x88D8
925#define GL_MATRIX25_ARB 0x88D9
926#define GL_MATRIX26_ARB 0x88DA
927#define GL_MATRIX27_ARB 0x88DB
928#define GL_MATRIX28_ARB 0x88DC
929#define GL_MATRIX29_ARB 0x88DD
930#define GL_MATRIX2_ARB 0x88C2
931#define GL_MATRIX30_ARB 0x88DE
932#define GL_MATRIX31_ARB 0x88DF
933#define GL_MATRIX3_ARB 0x88C3
934#define GL_MATRIX4_ARB 0x88C4
935#define GL_MATRIX5_ARB 0x88C5
936#define GL_MATRIX6_ARB 0x88C6
937#define GL_MATRIX7_ARB 0x88C7
938#define GL_MATRIX8_ARB 0x88C8
939#define GL_MATRIX9_ARB 0x88C9
940#define GL_MATRIX_STRIDE 0x92FF
941#define GL_MAX 0x8008
942#define GL_MAX_3D_TEXTURE_SIZE 0x8073
943#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF
944#define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC
945#define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8
946#define GL_MAX_CLIP_DISTANCES 0x0D32
947#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF
948#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF
949#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E
950#define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7
951#define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1
952#define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266
953#define GL_MAX_COMBINED_DIMENSIONS 0x8282
954#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33
955#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32
956#define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF
957#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39
958#define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39
959#define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC
960#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E
961#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F
962#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
963#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D
964#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E
965#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31
966#define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265
967#define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264
968#define GL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS_ARB 0x90EB
969#define GL_MAX_COMPUTE_FIXED_GROUP_SIZE_ARB 0x91BF
970#define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD
971#define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB
972#define GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262
973#define GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC
974#define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB
975#define GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263
976#define GL_MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB 0x9344
977#define GL_MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB 0x9345
978#define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE
979#define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB
980#define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF
981#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
982#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB 0x851C
983#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C
984#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144
985#define GL_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144
986#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143
987#define GL_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143
988#define GL_MAX_DEPTH 0x8280
989#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F
990#define GL_MAX_DRAW_BUFFERS 0x8824
991#define GL_MAX_DRAW_BUFFERS_ARB 0x8824
992#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC
993#define GL_MAX_ELEMENTS_INDICES 0x80E9
994#define GL_MAX_ELEMENTS_VERTICES 0x80E8
995#define GL_MAX_ELEMENT_INDEX 0x8D6B
996#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6
997#define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0
998#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE
999#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125
1000#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C
1001#define GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS 0x90DA
1002#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D
1003#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49
1004#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49
1005#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
1006#define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316
1007#define GL_MAX_FRAMEBUFFER_LAYERS 0x9317
1008#define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318
1009#define GL_MAX_FRAMEBUFFER_WIDTH 0x9315
1010#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5
1011#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF
1012#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD
1013#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123
1014#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124
1015#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0
1016#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB 0x8DE0
1017#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A
1018#define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7
1019#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29
1020#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB 0x8C29
1021#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1
1022#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB 0x8DE1
1023#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C
1024#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF
1025#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB 0x8DDF
1026#define GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB 0x8DDD
1027#define GL_MAX_HEIGHT 0x827F
1028#define GL_MAX_IMAGE_SAMPLES 0x906D
1029#define GL_MAX_IMAGE_UNITS 0x8F38
1030#define GL_MAX_INTEGER_SAMPLES 0x9110
1031#define GL_MAX_LABEL_LENGTH 0x82E8
1032#define GL_MAX_LAYERS 0x8281
1033#define GL_MAX_NAME_LENGTH 0x92F6
1034#define GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7
1035#define GL_MAX_NUM_COMPATIBLE_SUBROUTINES 0x92F8
1036#define GL_MAX_PATCH_VERTICES 0x8E7D
1037#define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1
1038#define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B
1039#define GL_MAX_PROGRAM_ATTRIBS_ARB 0x88AD
1040#define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5
1041#define GL_MAX_PROGRAM_INSTRUCTIONS_ARB 0x88A1
1042#define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4
1043#define GL_MAX_PROGRAM_MATRICES_ARB 0x862F
1044#define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E
1045#define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3
1046#define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E
1047#define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF
1048#define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3
1049#define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB
1050#define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7
1051#define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810
1052#define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F
1053#define GL_MAX_PROGRAM_PARAMETERS_ARB 0x88A9
1054#define GL_MAX_PROGRAM_TEMPORARIES_ARB 0x88A5
1055#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905
1056#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F
1057#define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D
1058#define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C
1059#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8
1060#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
1061#define GL_MAX_RENDERBUFFER_SIZE_EXT 0x84E8
1062#define GL_MAX_SAMPLES 0x8D57
1063#define GL_MAX_SAMPLES_EXT 0x8D57
1064#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59
1065#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111
1066#define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE
1067#define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD
1068#define GL_MAX_SUBROUTINES 0x8DE7
1069#define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8
1070#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3
1071#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD
1072#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB
1073#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C
1074#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83
1075#define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8
1076#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81
1077#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85
1078#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89
1079#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F
1080#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4
1081#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE
1082#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC
1083#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D
1084#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86
1085#define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS 0x90D9
1086#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82
1087#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A
1088#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80
1089#define GL_MAX_TESS_GEN_LEVEL 0x8E7E
1090#define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84
1091#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B
1092#define GL_MAX_TEXTURE_COORDS_ARB 0x8871
1093#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
1094#define GL_MAX_TEXTURE_IMAGE_UNITS_ARB 0x8872
1095#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD
1096#define GL_MAX_TEXTURE_MAX_ANISOTROPY 0x84FF
1097#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
1098#define GL_MAX_TEXTURE_SIZE 0x0D33
1099#define GL_MAX_TEXTURE_UNITS_ARB 0x84E2
1100#define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70
1101#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A
1102#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B
1103#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80
1104#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30
1105#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F
1106#define GL_MAX_UNIFORM_LOCATIONS 0x826E
1107#define GL_MAX_VARYING_COMPONENTS 0x8B4B
1108#define GL_MAX_VARYING_FLOATS 0x8B4B
1109#define GL_MAX_VARYING_FLOATS_ARB 0x8B4B
1110#define GL_MAX_VARYING_VECTORS 0x8DFC
1111#define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2
1112#define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC
1113#define GL_MAX_VERTEX_ATTRIBS 0x8869
1114#define GL_MAX_VERTEX_ATTRIBS_ARB 0x8869
1115#define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA
1116#define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9
1117#define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA
1118#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122
1119#define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6
1120#define GL_MAX_VERTEX_STREAMS 0x8E71
1121#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
1122#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C
1123#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B
1124#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A
1125#define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A
1126#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
1127#define GL_MAX_VERTEX_VARYING_COMPONENTS_ARB 0x8DDE
1128#define GL_MAX_VIEWPORTS 0x825B
1129#define GL_MAX_VIEWPORT_DIMS 0x0D3A
1130#define GL_MAX_WIDTH 0x827E
1131#define GL_MEDIUM_FLOAT 0x8DF1
1132#define GL_MEDIUM_INT 0x8DF4
1133#define GL_MIN 0x8007
1134#define GL_MINOR_VERSION 0x821C
1135#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B
1136#define GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC
1137#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904
1138#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E
1139#define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37
1140#define GL_MIN_SAMPLE_SHADING_VALUE_ARB 0x8C37
1141#define GL_MIPMAP 0x8293
1142#define GL_MIRRORED_REPEAT 0x8370
1143#define GL_MIRRORED_REPEAT_ARB 0x8370
1144#define GL_MIRROR_CLAMP_EXT 0x8742
1145#define GL_MIRROR_CLAMP_TO_BORDER_EXT 0x8912
1146#define GL_MIRROR_CLAMP_TO_EDGE 0x8743
1147#define GL_MIRROR_CLAMP_TO_EDGE_EXT 0x8743
1148#define GL_MULTISAMPLE 0x809D
1149#define GL_MULTISAMPLE_ARB 0x809D
1150#define GL_MULTISAMPLE_BIT_ARB 0x20000000
1151#define GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY_ARB 0x9382
1152#define GL_MULTISAMPLE_LINE_WIDTH_RANGE_ARB 0x9381
1153#define GL_NAMED_STRING_LENGTH_ARB 0x8DE9
1154#define GL_NAMED_STRING_TYPE_ARB 0x8DEA
1155#define GL_NAME_LENGTH 0x92F9
1156#define GL_NAND 0x150E
1157#define GL_NEAREST 0x2600
1158#define GL_NEAREST_MIPMAP_LINEAR 0x2702
1159#define GL_NEAREST_MIPMAP_NEAREST 0x2700
1160#define GL_NEVER 0x0200
1161#define GL_NICEST 0x1102
1162#define GL_NONE 0
1163#define GL_NOOP 0x1505
1164#define GL_NOR 0x1508
1165#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897
1166#define GL_NORMAL_MAP_ARB 0x8511
1167#define GL_NOTEQUAL 0x0205
1168#define GL_NO_ERROR 0
1169#define GL_NUM_ACTIVE_VARIABLES 0x9304
1170#define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A
1171#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
1172#define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2
1173#define GL_NUM_EXTENSIONS 0x821D
1174#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
1175#define GL_NUM_SAMPLE_COUNTS 0x9380
1176#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
1177#define GL_NUM_SHADING_LANGUAGE_VERSIONS 0x82E9
1178#define GL_NUM_SPIR_V_EXTENSIONS 0x9554
1179#define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB 0x8B89
1180#define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A
1181#define GL_OBJECT_ACTIVE_UNIFORMS_ARB 0x8B86
1182#define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87
1183#define GL_OBJECT_ATTACHED_OBJECTS_ARB 0x8B85
1184#define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81
1185#define GL_OBJECT_DELETE_STATUS_ARB 0x8B80
1186#define GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84
1187#define GL_OBJECT_LINK_STATUS_ARB 0x8B82
1188#define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88
1189#define GL_OBJECT_SUBTYPE_ARB 0x8B4F
1190#define GL_OBJECT_TYPE 0x9112
1191#define GL_OBJECT_TYPE_ARB 0x8B4E
1192#define GL_OBJECT_VALIDATE_STATUS_ARB 0x8B83
1193#define GL_OFFSET 0x92FC
1194#define GL_ONE 1
1195#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
1196#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
1197#define GL_ONE_MINUS_DST_ALPHA 0x0305
1198#define GL_ONE_MINUS_DST_COLOR 0x0307
1199#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB
1200#define GL_ONE_MINUS_SRC1_COLOR 0x88FA
1201#define GL_ONE_MINUS_SRC_ALPHA 0x0303
1202#define GL_ONE_MINUS_SRC_COLOR 0x0301
1203#define GL_OR 0x1507
1204#define GL_OR_INVERTED 0x150D
1205#define GL_OR_REVERSE 0x150B
1206#define GL_OUT_OF_MEMORY 0x0505
1207#define GL_PACK_ALIGNMENT 0x0D05
1208#define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D
1209#define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C
1210#define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E
1211#define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B
1212#define GL_PACK_IMAGE_HEIGHT 0x806C
1213#define GL_PACK_LSB_FIRST 0x0D01
1214#define GL_PACK_ROW_LENGTH 0x0D02
1215#define GL_PACK_SKIP_IMAGES 0x806B
1216#define GL_PACK_SKIP_PIXELS 0x0D04
1217#define GL_PACK_SKIP_ROWS 0x0D03
1218#define GL_PACK_SWAP_BYTES 0x0D00
1219#define GL_PALETTE4_R5_G6_B5_OES 0x8B92
1220#define GL_PALETTE4_RGB5_A1_OES 0x8B94
1221#define GL_PALETTE4_RGB8_OES 0x8B90
1222#define GL_PALETTE4_RGBA4_OES 0x8B93
1223#define GL_PALETTE4_RGBA8_OES 0x8B91
1224#define GL_PALETTE8_R5_G6_B5_OES 0x8B97
1225#define GL_PALETTE8_RGB5_A1_OES 0x8B99
1226#define GL_PALETTE8_RGB8_OES 0x8B95
1227#define GL_PALETTE8_RGBA4_OES 0x8B98
1228#define GL_PALETTE8_RGBA8_OES 0x8B96
1229#define GL_PATCHES 0x000E
1230#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73
1231#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74
1232#define GL_PATCH_VERTICES 0x8E72
1233#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080
1234#define GL_PIXEL_PACK_BUFFER 0x88EB
1235#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED
1236#define GL_PIXEL_UNPACK_BUFFER 0x88EC
1237#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF
1238#define GL_POINT 0x1B00
1239#define GL_POINTS 0x0000
1240#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128
1241#define GL_POINT_SIZE 0x0B11
1242#define GL_POINT_SIZE_GRANULARITY 0x0B13
1243#define GL_POINT_SIZE_RANGE 0x0B12
1244#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0
1245#define GL_POLYGON_MODE 0x0B40
1246#define GL_POLYGON_OFFSET_FACTOR 0x8038
1247#define GL_POLYGON_OFFSET_FILL 0x8037
1248#define GL_POLYGON_OFFSET_LINE 0x2A02
1249#define GL_POLYGON_OFFSET_POINT 0x2A01
1250#define GL_POLYGON_OFFSET_UNITS 0x2A00
1251#define GL_POLYGON_SMOOTH 0x0B41
1252#define GL_POLYGON_SMOOTH_HINT 0x0C53
1253#define GL_PRIMITIVES_GENERATED 0x8C87
1254#define GL_PRIMITIVES_SUBMITTED 0x82EF
1255#define GL_PRIMITIVES_SUBMITTED_ARB 0x82EF
1256#define GL_PRIMITIVE_BOUNDING_BOX_ARB 0x92BE
1257#define GL_PRIMITIVE_RESTART 0x8F9D
1258#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69
1259#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E
1260#define GL_PROGRAM 0x82E2
1261#define GL_PROGRAMMABLE_SAMPLE_LOCATION_ARB 0x9341
1262#define GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_ARB 0x9340
1263#define GL_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B0
1264#define GL_PROGRAM_ALU_INSTRUCTIONS_ARB 0x8805
1265#define GL_PROGRAM_ATTRIBS_ARB 0x88AC
1266#define GL_PROGRAM_BINARY_FORMATS 0x87FF
1267#define GL_PROGRAM_BINARY_LENGTH 0x8741
1268#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257
1269#define GL_PROGRAM_BINDING_ARB 0x8677
1270#define GL_PROGRAM_ERROR_POSITION_ARB 0x864B
1271#define GL_PROGRAM_ERROR_STRING_ARB 0x8874
1272#define GL_PROGRAM_FORMAT_ARB 0x8876
1273#define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875
1274#define GL_PROGRAM_INPUT 0x92E3
1275#define GL_PROGRAM_INSTRUCTIONS_ARB 0x88A0
1276#define GL_PROGRAM_LENGTH_ARB 0x8627
1277#define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2
1278#define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808
1279#define GL_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AE
1280#define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2
1281#define GL_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AA
1282#define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6
1283#define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A
1284#define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809
1285#define GL_PROGRAM_OBJECT_ARB 0x8B40
1286#define GL_PROGRAM_OUTPUT 0x92E4
1287#define GL_PROGRAM_PARAMETERS_ARB 0x88A8
1288#define GL_PROGRAM_PIPELINE 0x82E4
1289#define GL_PROGRAM_PIPELINE_BINDING 0x825A
1290#define GL_PROGRAM_POINT_SIZE 0x8642
1291#define GL_PROGRAM_POINT_SIZE_ARB 0x8642
1292#define GL_PROGRAM_SEPARABLE 0x8258
1293#define GL_PROGRAM_STRING_ARB 0x8628
1294#define GL_PROGRAM_TEMPORARIES_ARB 0x88A4
1295#define GL_PROGRAM_TEX_INDIRECTIONS_ARB 0x8807
1296#define GL_PROGRAM_TEX_INSTRUCTIONS_ARB 0x8806
1297#define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6
1298#define GL_PROVOKING_VERTEX 0x8E4F
1299#define GL_PROXY_TEXTURE_1D 0x8063
1300#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19
1301#define GL_PROXY_TEXTURE_2D 0x8064
1302#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B
1303#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101
1304#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103
1305#define GL_PROXY_TEXTURE_3D 0x8070
1306#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B
1307#define GL_PROXY_TEXTURE_CUBE_MAP_ARB 0x851B
1308#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B
1309#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB 0x900B
1310#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7
1311#define GL_QUADS 0x0007
1312#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C
1313#define GL_QUERY 0x82E3
1314#define GL_QUERY_BUFFER 0x9192
1315#define GL_QUERY_BUFFER_BARRIER_BIT 0x00008000
1316#define GL_QUERY_BUFFER_BINDING 0x9193
1317#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16
1318#define GL_QUERY_BY_REGION_WAIT 0x8E15
1319#define GL_QUERY_COUNTER_BITS 0x8864
1320#define GL_QUERY_COUNTER_BITS_ARB 0x8864
1321#define GL_QUERY_NO_WAIT 0x8E14
1322#define GL_QUERY_RESULT 0x8866
1323#define GL_QUERY_RESULT_ARB 0x8866
1324#define GL_QUERY_RESULT_AVAILABLE 0x8867
1325#define GL_QUERY_RESULT_AVAILABLE_ARB 0x8867
1326#define GL_QUERY_RESULT_NO_WAIT 0x9194
1327#define GL_QUERY_TARGET 0x82EA
1328#define GL_QUERY_WAIT 0x8E13
1329#define GL_R11F_G11F_B10F 0x8C3A
1330#define GL_R16 0x822A
1331#define GL_R16F 0x822D
1332#define GL_R16I 0x8233
1333#define GL_R16UI 0x8234
1334#define GL_R16_SNORM 0x8F98
1335#define GL_R32F 0x822E
1336#define GL_R32I 0x8235
1337#define GL_R32UI 0x8236
1338#define GL_R3_G3_B2 0x2A10
1339#define GL_R8 0x8229
1340#define GL_R8I 0x8231
1341#define GL_R8UI 0x8232
1342#define GL_R8_SNORM 0x8F94
1343#define GL_RASTERIZER_DISCARD 0x8C89
1344#define GL_READ_BUFFER 0x0C02
1345#define GL_READ_FRAMEBUFFER 0x8CA8
1346#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA
1347#define GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA
1348#define GL_READ_FRAMEBUFFER_EXT 0x8CA8
1349#define GL_READ_ONLY 0x88B8
1350#define GL_READ_ONLY_ARB 0x88B8
1351#define GL_READ_PIXELS 0x828C
1352#define GL_READ_PIXELS_FORMAT 0x828D
1353#define GL_READ_PIXELS_TYPE 0x828E
1354#define GL_READ_WRITE 0x88BA
1355#define GL_READ_WRITE_ARB 0x88BA
1356#define GL_RED 0x1903
1357#define GL_RED_INTEGER 0x8D94
1358#define GL_REFERENCED_BY_COMPUTE_SHADER 0x930B
1359#define GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A
1360#define GL_REFERENCED_BY_GEOMETRY_SHADER 0x9309
1361#define GL_REFERENCED_BY_TESS_CONTROL_SHADER 0x9307
1362#define GL_REFERENCED_BY_TESS_EVALUATION_SHADER 0x9308
1363#define GL_REFERENCED_BY_VERTEX_SHADER 0x9306
1364#define GL_REFLECTION_MAP_ARB 0x8512
1365#define GL_RENDERBUFFER 0x8D41
1366#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53
1367#define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53
1368#define GL_RENDERBUFFER_BINDING 0x8CA7
1369#define GL_RENDERBUFFER_BINDING_EXT 0x8CA7
1370#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52
1371#define GL_RENDERBUFFER_BLUE_SIZE_EXT 0x8D52
1372#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54
1373#define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54
1374#define GL_RENDERBUFFER_EXT 0x8D41
1375#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51
1376#define GL_RENDERBUFFER_GREEN_SIZE_EXT 0x8D51
1377#define GL_RENDERBUFFER_HEIGHT 0x8D43
1378#define GL_RENDERBUFFER_HEIGHT_EXT 0x8D43
1379#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
1380#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44
1381#define GL_RENDERBUFFER_RED_SIZE 0x8D50
1382#define GL_RENDERBUFFER_RED_SIZE_EXT 0x8D50
1383#define GL_RENDERBUFFER_SAMPLES 0x8CAB
1384#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB
1385#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
1386#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55
1387#define GL_RENDERBUFFER_WIDTH 0x8D42
1388#define GL_RENDERBUFFER_WIDTH_EXT 0x8D42
1389#define GL_RENDERER 0x1F01
1390#define GL_REPEAT 0x2901
1391#define GL_REPLACE 0x1E01
1392#define GL_RG 0x8227
1393#define GL_RG16 0x822C
1394#define GL_RG16F 0x822F
1395#define GL_RG16I 0x8239
1396#define GL_RG16UI 0x823A
1397#define GL_RG16_SNORM 0x8F99
1398#define GL_RG32F 0x8230
1399#define GL_RG32I 0x823B
1400#define GL_RG32UI 0x823C
1401#define GL_RG8 0x822B
1402#define GL_RG8I 0x8237
1403#define GL_RG8UI 0x8238
1404#define GL_RG8_SNORM 0x8F95
1405#define GL_RGB 0x1907
1406#define GL_RGB10 0x8052
1407#define GL_RGB10_A2 0x8059
1408#define GL_RGB10_A2UI 0x906F
1409#define GL_RGB12 0x8053
1410#define GL_RGB16 0x8054
1411#define GL_RGB16F 0x881B
1412#define GL_RGB16F_ARB 0x881B
1413#define GL_RGB16I 0x8D89
1414#define GL_RGB16UI 0x8D77
1415#define GL_RGB16_SNORM 0x8F9A
1416#define GL_RGB32F 0x8815
1417#define GL_RGB32F_ARB 0x8815
1418#define GL_RGB32I 0x8D83
1419#define GL_RGB32UI 0x8D71
1420#define GL_RGB4 0x804F
1421#define GL_RGB5 0x8050
1422#define GL_RGB565 0x8D62
1423#define GL_RGB5_A1 0x8057
1424#define GL_RGB8 0x8051
1425#define GL_RGB8I 0x8D8F
1426#define GL_RGB8UI 0x8D7D
1427#define GL_RGB8_SNORM 0x8F96
1428#define GL_RGB9_E5 0x8C3D
1429#define GL_RGBA 0x1908
1430#define GL_RGBA12 0x805A
1431#define GL_RGBA16 0x805B
1432#define GL_RGBA16F 0x881A
1433#define GL_RGBA16F_ARB 0x881A
1434#define GL_RGBA16I 0x8D88
1435#define GL_RGBA16UI 0x8D76
1436#define GL_RGBA16_SNORM 0x8F9B
1437#define GL_RGBA2 0x8055
1438#define GL_RGBA32F 0x8814
1439#define GL_RGBA32F_ARB 0x8814
1440#define GL_RGBA32I 0x8D82
1441#define GL_RGBA32UI 0x8D70
1442#define GL_RGBA4 0x8056
1443#define GL_RGBA8 0x8058
1444#define GL_RGBA8I 0x8D8E
1445#define GL_RGBA8UI 0x8D7C
1446#define GL_RGBA8_SNORM 0x8F97
1447#define GL_RGBA_FLOAT_MODE_ARB 0x8820
1448#define GL_RGBA_INTEGER 0x8D99
1449#define GL_RGB_INTEGER 0x8D98
1450#define GL_RG_INTEGER 0x8228
1451#define GL_RIGHT 0x0407
1452#define GL_SAMPLER 0x82E6
1453#define GL_SAMPLER_1D 0x8B5D
1454#define GL_SAMPLER_1D_ARB 0x8B5D
1455#define GL_SAMPLER_1D_ARRAY 0x8DC0
1456#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3
1457#define GL_SAMPLER_1D_SHADOW 0x8B61
1458#define GL_SAMPLER_1D_SHADOW_ARB 0x8B61
1459#define GL_SAMPLER_2D 0x8B5E
1460#define GL_SAMPLER_2D_ARB 0x8B5E
1461#define GL_SAMPLER_2D_ARRAY 0x8DC1
1462#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4
1463#define GL_SAMPLER_2D_MULTISAMPLE 0x9108
1464#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B
1465#define GL_SAMPLER_2D_RECT 0x8B63
1466#define GL_SAMPLER_2D_RECT_ARB 0x8B63
1467#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64
1468#define GL_SAMPLER_2D_RECT_SHADOW_ARB 0x8B64
1469#define GL_SAMPLER_2D_SHADOW 0x8B62
1470#define GL_SAMPLER_2D_SHADOW_ARB 0x8B62
1471#define GL_SAMPLER_3D 0x8B5F
1472#define GL_SAMPLER_3D_ARB 0x8B5F
1473#define GL_SAMPLER_BINDING 0x8919
1474#define GL_SAMPLER_BUFFER 0x8DC2
1475#define GL_SAMPLER_CUBE 0x8B60
1476#define GL_SAMPLER_CUBE_ARB 0x8B60
1477#define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C
1478#define GL_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900C
1479#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D
1480#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB 0x900D
1481#define GL_SAMPLER_CUBE_SHADOW 0x8DC5
1482#define GL_SAMPLES 0x80A9
1483#define GL_SAMPLES_ARB 0x80A9
1484#define GL_SAMPLES_PASSED 0x8914
1485#define GL_SAMPLES_PASSED_ARB 0x8914
1486#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
1487#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E
1488#define GL_SAMPLE_ALPHA_TO_ONE 0x809F
1489#define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F
1490#define GL_SAMPLE_BUFFERS 0x80A8
1491#define GL_SAMPLE_BUFFERS_ARB 0x80A8
1492#define GL_SAMPLE_COVERAGE 0x80A0
1493#define GL_SAMPLE_COVERAGE_ARB 0x80A0
1494#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
1495#define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB
1496#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
1497#define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA
1498#define GL_SAMPLE_LOCATION_ARB 0x8E50
1499#define GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_ARB 0x933F
1500#define GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_ARB 0x933E
1501#define GL_SAMPLE_LOCATION_SUBPIXEL_BITS_ARB 0x933D
1502#define GL_SAMPLE_MASK 0x8E51
1503#define GL_SAMPLE_MASK_VALUE 0x8E52
1504#define GL_SAMPLE_POSITION 0x8E50
1505#define GL_SAMPLE_SHADING 0x8C36
1506#define GL_SAMPLE_SHADING_ARB 0x8C36
1507#define GL_SCISSOR_BOX 0x0C10
1508#define GL_SCISSOR_TEST 0x0C11
1509#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C
1510#define GL_SEPARATE_ATTRIBS 0x8C8D
1511#define GL_SET 0x150F
1512#define GL_SHADER 0x82E1
1513#define GL_SHADER_BINARY_FORMATS 0x8DF8
1514#define GL_SHADER_BINARY_FORMAT_SPIR_V 0x9551
1515#define GL_SHADER_BINARY_FORMAT_SPIR_V_ARB 0x9551
1516#define GL_SHADER_COMPILER 0x8DFA
1517#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
1518#define GL_SHADER_IMAGE_ATOMIC 0x82A6
1519#define GL_SHADER_IMAGE_LOAD 0x82A4
1520#define GL_SHADER_IMAGE_STORE 0x82A5
1521#define GL_SHADER_INCLUDE_ARB 0x8DAE
1522#define GL_SHADER_OBJECT_ARB 0x8B48
1523#define GL_SHADER_SOURCE_LENGTH 0x8B88
1524#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000
1525#define GL_SHADER_STORAGE_BLOCK 0x92E6
1526#define GL_SHADER_STORAGE_BUFFER 0x90D2
1527#define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3
1528#define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF
1529#define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5
1530#define GL_SHADER_STORAGE_BUFFER_START 0x90D4
1531#define GL_SHADER_TYPE 0x8B4F
1532#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
1533#define GL_SHADING_LANGUAGE_VERSION_ARB 0x8B8C
1534#define GL_SHORT 0x1402
1535#define GL_SIGNALED 0x9119
1536#define GL_SIGNED_NORMALIZED 0x8F9C
1537#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST 0x82AC
1538#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE 0x82AE
1539#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST 0x82AD
1540#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE 0x82AF
1541#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23
1542#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22
1543#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13
1544#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12
1545#define GL_SOURCE1_ALPHA 0x8589
1546#define GL_SPIR_V_BINARY 0x9552
1547#define GL_SPIR_V_BINARY_ARB 0x9552
1548#define GL_SPIR_V_EXTENSIONS 0x9553
1549#define GL_SRC1_ALPHA 0x8589
1550#define GL_SRC1_COLOR 0x88F9
1551#define GL_SRC_ALPHA 0x0302
1552#define GL_SRC_ALPHA_SATURATE 0x0308
1553#define GL_SRC_COLOR 0x0300
1554#define GL_SRGB 0x8C40
1555#define GL_SRGB8 0x8C41
1556#define GL_SRGB8_ALPHA8 0x8C43
1557#define GL_SRGB_ALPHA 0x8C42
1558#define GL_SRGB_DECODE_ARB 0x8299
1559#define GL_SRGB_READ 0x8297
1560#define GL_SRGB_WRITE 0x8298
1561#define GL_STACK_OVERFLOW 0x0503
1562#define GL_STACK_UNDERFLOW 0x0504
1563#define GL_STATIC_COPY 0x88E6
1564#define GL_STATIC_COPY_ARB 0x88E6
1565#define GL_STATIC_DRAW 0x88E4
1566#define GL_STATIC_DRAW_ARB 0x88E4
1567#define GL_STATIC_READ 0x88E5
1568#define GL_STATIC_READ_ARB 0x88E5
1569#define GL_STENCIL 0x1802
1570#define GL_STENCIL_ATTACHMENT 0x8D20
1571#define GL_STENCIL_ATTACHMENT_EXT 0x8D20
1572#define GL_STENCIL_BACK_FAIL 0x8801
1573#define GL_STENCIL_BACK_FUNC 0x8800
1574#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
1575#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
1576#define GL_STENCIL_BACK_REF 0x8CA3
1577#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4
1578#define GL_STENCIL_BACK_WRITEMASK 0x8CA5
1579#define GL_STENCIL_BUFFER_BIT 0x00000400
1580#define GL_STENCIL_CLEAR_VALUE 0x0B91
1581#define GL_STENCIL_COMPONENTS 0x8285
1582#define GL_STENCIL_FAIL 0x0B94
1583#define GL_STENCIL_FUNC 0x0B92
1584#define GL_STENCIL_INDEX 0x1901
1585#define GL_STENCIL_INDEX1 0x8D46
1586#define GL_STENCIL_INDEX16 0x8D49
1587#define GL_STENCIL_INDEX16_EXT 0x8D49
1588#define GL_STENCIL_INDEX1_EXT 0x8D46
1589#define GL_STENCIL_INDEX4 0x8D47
1590#define GL_STENCIL_INDEX4_EXT 0x8D47
1591#define GL_STENCIL_INDEX8 0x8D48
1592#define GL_STENCIL_INDEX8_EXT 0x8D48
1593#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
1594#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
1595#define GL_STENCIL_REF 0x0B97
1596#define GL_STENCIL_RENDERABLE 0x8288
1597#define GL_STENCIL_TEST 0x0B90
1598#define GL_STENCIL_VALUE_MASK 0x0B93
1599#define GL_STENCIL_WRITEMASK 0x0B98
1600#define GL_STEREO 0x0C33
1601#define GL_STREAM_COPY 0x88E2
1602#define GL_STREAM_COPY_ARB 0x88E2
1603#define GL_STREAM_DRAW 0x88E0
1604#define GL_STREAM_DRAW_ARB 0x88E0
1605#define GL_STREAM_READ 0x88E1
1606#define GL_STREAM_READ_ARB 0x88E1
1607#define GL_SUBPIXEL_BITS 0x0D50
1608#define GL_SYNC_CONDITION 0x9113
1609#define GL_SYNC_FENCE 0x9116
1610#define GL_SYNC_FLAGS 0x9115
1611#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001
1612#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117
1613#define GL_SYNC_STATUS 0x9114
1614#define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75
1615#define GL_TESS_CONTROL_SHADER 0x8E88
1616#define GL_TESS_CONTROL_SHADER_BIT 0x00000008
1617#define GL_TESS_CONTROL_SHADER_PATCHES 0x82F1
1618#define GL_TESS_CONTROL_SHADER_PATCHES_ARB 0x82F1
1619#define GL_TESS_CONTROL_SUBROUTINE 0x92E9
1620#define GL_TESS_CONTROL_SUBROUTINE_UNIFORM 0x92EF
1621#define GL_TESS_CONTROL_TEXTURE 0x829C
1622#define GL_TESS_EVALUATION_SHADER 0x8E87
1623#define GL_TESS_EVALUATION_SHADER_BIT 0x00000010
1624#define GL_TESS_EVALUATION_SHADER_INVOCATIONS 0x82F2
1625#define GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB 0x82F2
1626#define GL_TESS_EVALUATION_SUBROUTINE 0x92EA
1627#define GL_TESS_EVALUATION_SUBROUTINE_UNIFORM 0x92F0
1628#define GL_TESS_EVALUATION_TEXTURE 0x829D
1629#define GL_TESS_GEN_MODE 0x8E76
1630#define GL_TESS_GEN_POINT_MODE 0x8E79
1631#define GL_TESS_GEN_SPACING 0x8E77
1632#define GL_TESS_GEN_VERTEX_ORDER 0x8E78
1633#define GL_TEXTURE 0x1702
1634#define GL_TEXTURE0 0x84C0
1635#define GL_TEXTURE0_ARB 0x84C0
1636#define GL_TEXTURE1 0x84C1
1637#define GL_TEXTURE10 0x84CA
1638#define GL_TEXTURE10_ARB 0x84CA
1639#define GL_TEXTURE11 0x84CB
1640#define GL_TEXTURE11_ARB 0x84CB
1641#define GL_TEXTURE12 0x84CC
1642#define GL_TEXTURE12_ARB 0x84CC
1643#define GL_TEXTURE13 0x84CD
1644#define GL_TEXTURE13_ARB 0x84CD
1645#define GL_TEXTURE14 0x84CE
1646#define GL_TEXTURE14_ARB 0x84CE
1647#define GL_TEXTURE15 0x84CF
1648#define GL_TEXTURE15_ARB 0x84CF
1649#define GL_TEXTURE16 0x84D0
1650#define GL_TEXTURE16_ARB 0x84D0
1651#define GL_TEXTURE17 0x84D1
1652#define GL_TEXTURE17_ARB 0x84D1
1653#define GL_TEXTURE18 0x84D2
1654#define GL_TEXTURE18_ARB 0x84D2
1655#define GL_TEXTURE19 0x84D3
1656#define GL_TEXTURE19_ARB 0x84D3
1657#define GL_TEXTURE1_ARB 0x84C1
1658#define GL_TEXTURE2 0x84C2
1659#define GL_TEXTURE20 0x84D4
1660#define GL_TEXTURE20_ARB 0x84D4
1661#define GL_TEXTURE21 0x84D5
1662#define GL_TEXTURE21_ARB 0x84D5
1663#define GL_TEXTURE22 0x84D6
1664#define GL_TEXTURE22_ARB 0x84D6
1665#define GL_TEXTURE23 0x84D7
1666#define GL_TEXTURE23_ARB 0x84D7
1667#define GL_TEXTURE24 0x84D8
1668#define GL_TEXTURE24_ARB 0x84D8
1669#define GL_TEXTURE25 0x84D9
1670#define GL_TEXTURE25_ARB 0x84D9
1671#define GL_TEXTURE26 0x84DA
1672#define GL_TEXTURE26_ARB 0x84DA
1673#define GL_TEXTURE27 0x84DB
1674#define GL_TEXTURE27_ARB 0x84DB
1675#define GL_TEXTURE28 0x84DC
1676#define GL_TEXTURE28_ARB 0x84DC
1677#define GL_TEXTURE29 0x84DD
1678#define GL_TEXTURE29_ARB 0x84DD
1679#define GL_TEXTURE2_ARB 0x84C2
1680#define GL_TEXTURE3 0x84C3
1681#define GL_TEXTURE30 0x84DE
1682#define GL_TEXTURE30_ARB 0x84DE
1683#define GL_TEXTURE31 0x84DF
1684#define GL_TEXTURE31_ARB 0x84DF
1685#define GL_TEXTURE3_ARB 0x84C3
1686#define GL_TEXTURE4 0x84C4
1687#define GL_TEXTURE4_ARB 0x84C4
1688#define GL_TEXTURE5 0x84C5
1689#define GL_TEXTURE5_ARB 0x84C5
1690#define GL_TEXTURE6 0x84C6
1691#define GL_TEXTURE6_ARB 0x84C6
1692#define GL_TEXTURE7 0x84C7
1693#define GL_TEXTURE7_ARB 0x84C7
1694#define GL_TEXTURE8 0x84C8
1695#define GL_TEXTURE8_ARB 0x84C8
1696#define GL_TEXTURE9 0x84C9
1697#define GL_TEXTURE9_ARB 0x84C9
1698#define GL_TEXTURE_1D 0x0DE0
1699#define GL_TEXTURE_1D_ARRAY 0x8C18
1700#define GL_TEXTURE_2D 0x0DE1
1701#define GL_TEXTURE_2D_ARRAY 0x8C1A
1702#define GL_TEXTURE_2D_MULTISAMPLE 0x9100
1703#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102
1704#define GL_TEXTURE_3D 0x806F
1705#define GL_TEXTURE_ALPHA_SIZE 0x805F
1706#define GL_TEXTURE_ALPHA_TYPE 0x8C13
1707#define GL_TEXTURE_ALPHA_TYPE_ARB 0x8C13
1708#define GL_TEXTURE_BASE_LEVEL 0x813C
1709#define GL_TEXTURE_BINDING_1D 0x8068
1710#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C
1711#define GL_TEXTURE_BINDING_2D 0x8069
1712#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D
1713#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104
1714#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105
1715#define GL_TEXTURE_BINDING_3D 0x806A
1716#define GL_TEXTURE_BINDING_BUFFER 0x8C2C
1717#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
1718#define GL_TEXTURE_BINDING_CUBE_MAP_ARB 0x8514
1719#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A
1720#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_ARB 0x900A
1721#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6
1722#define GL_TEXTURE_BLUE_SIZE 0x805E
1723#define GL_TEXTURE_BLUE_TYPE 0x8C12
1724#define GL_TEXTURE_BLUE_TYPE_ARB 0x8C12
1725#define GL_TEXTURE_BORDER_COLOR 0x1004
1726#define GL_TEXTURE_BUFFER 0x8C2A
1727#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D
1728#define GL_TEXTURE_BUFFER_OFFSET 0x919D
1729#define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT 0x919F
1730#define GL_TEXTURE_BUFFER_SIZE 0x919E
1731#define GL_TEXTURE_COMPARE_FUNC 0x884D
1732#define GL_TEXTURE_COMPARE_MODE 0x884C
1733#define GL_TEXTURE_COMPRESSED 0x86A1
1734#define GL_TEXTURE_COMPRESSED_ARB 0x86A1
1735#define GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT 0x82B2
1736#define GL_TEXTURE_COMPRESSED_BLOCK_SIZE 0x82B3
1737#define GL_TEXTURE_COMPRESSED_BLOCK_WIDTH 0x82B1
1738#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0
1739#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0
1740#define GL_TEXTURE_COMPRESSION_HINT 0x84EF
1741#define GL_TEXTURE_COMPRESSION_HINT_ARB 0x84EF
1742#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A
1743#define GL_TEXTURE_CUBE_MAP 0x8513
1744#define GL_TEXTURE_CUBE_MAP_ARB 0x8513
1745#define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009
1746#define GL_TEXTURE_CUBE_MAP_ARRAY_ARB 0x9009
1747#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
1748#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516
1749#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
1750#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518
1751#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
1752#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A
1753#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
1754#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515
1755#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
1756#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517
1757#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
1758#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519
1759#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F
1760#define GL_TEXTURE_DEPTH 0x8071
1761#define GL_TEXTURE_DEPTH_SIZE 0x884A
1762#define GL_TEXTURE_DEPTH_SIZE_ARB 0x884A
1763#define GL_TEXTURE_DEPTH_TYPE 0x8C16
1764#define GL_TEXTURE_DEPTH_TYPE_ARB 0x8C16
1765#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008
1766#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107
1767#define GL_TEXTURE_GATHER 0x82A2
1768#define GL_TEXTURE_GATHER_SHADOW 0x82A3
1769#define GL_TEXTURE_GREEN_SIZE 0x805D
1770#define GL_TEXTURE_GREEN_TYPE 0x8C11
1771#define GL_TEXTURE_GREEN_TYPE_ARB 0x8C11
1772#define GL_TEXTURE_HEIGHT 0x1001
1773#define GL_TEXTURE_IMAGE_FORMAT 0x828F
1774#define GL_TEXTURE_IMAGE_TYPE 0x8290
1775#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F
1776#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF
1777#define GL_TEXTURE_INTENSITY_TYPE_ARB 0x8C15
1778#define GL_TEXTURE_INTERNAL_FORMAT 0x1003
1779#define GL_TEXTURE_LOD_BIAS 0x8501
1780#define GL_TEXTURE_LUMINANCE_TYPE_ARB 0x8C14
1781#define GL_TEXTURE_MAG_FILTER 0x2800
1782#define GL_TEXTURE_MAX_ANISOTROPY 0x84FE
1783#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
1784#define GL_TEXTURE_MAX_LEVEL 0x813D
1785#define GL_TEXTURE_MAX_LOD 0x813B
1786#define GL_TEXTURE_MIN_FILTER 0x2801
1787#define GL_TEXTURE_MIN_LOD 0x813A
1788#define GL_TEXTURE_RECTANGLE 0x84F5
1789#define GL_TEXTURE_REDUCTION_MODE_ARB 0x9366
1790#define GL_TEXTURE_RED_SIZE 0x805C
1791#define GL_TEXTURE_RED_TYPE 0x8C10
1792#define GL_TEXTURE_RED_TYPE_ARB 0x8C10
1793#define GL_TEXTURE_SAMPLES 0x9106
1794#define GL_TEXTURE_SHADOW 0x82A1
1795#define GL_TEXTURE_SHARED_SIZE 0x8C3F
1796#define GL_TEXTURE_STENCIL_SIZE 0x88F1
1797#define GL_TEXTURE_SWIZZLE_A 0x8E45
1798#define GL_TEXTURE_SWIZZLE_B 0x8E44
1799#define GL_TEXTURE_SWIZZLE_G 0x8E43
1800#define GL_TEXTURE_SWIZZLE_R 0x8E42
1801#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46
1802#define GL_TEXTURE_TARGET 0x1006
1803#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100
1804#define GL_TEXTURE_VIEW 0x82B5
1805#define GL_TEXTURE_VIEW_MIN_LAYER 0x82DD
1806#define GL_TEXTURE_VIEW_MIN_LEVEL 0x82DB
1807#define GL_TEXTURE_VIEW_NUM_LAYERS 0x82DE
1808#define GL_TEXTURE_VIEW_NUM_LEVELS 0x82DC
1809#define GL_TEXTURE_WIDTH 0x1000
1810#define GL_TEXTURE_WRAP_R 0x8072
1811#define GL_TEXTURE_WRAP_S 0x2802
1812#define GL_TEXTURE_WRAP_T 0x2803
1813#define GL_TIMEOUT_EXPIRED 0x911B
1814#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFF
1815#define GL_TIMESTAMP 0x8E28
1816#define GL_TIME_ELAPSED 0x88BF
1817#define GL_TOP_LEVEL_ARRAY_SIZE 0x930C
1818#define GL_TOP_LEVEL_ARRAY_STRIDE 0x930D
1819#define GL_TRANSFORM_FEEDBACK 0x8E22
1820#define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24
1821#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800
1822#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25
1823#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E
1824#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24
1825#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F
1826#define GL_TRANSFORM_FEEDBACK_BUFFER_INDEX 0x934B
1827#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F
1828#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23
1829#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85
1830#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84
1831#define GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE 0x934C
1832#define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23
1833#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88
1834#define GL_TRANSFORM_FEEDBACK_VARYING 0x92F4
1835#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83
1836#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76
1837#define GL_TRANSPOSE_COLOR_MATRIX_ARB 0x84E6
1838#define GL_TRANSPOSE_CURRENT_MATRIX_ARB 0x88B7
1839#define GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3
1840#define GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4
1841#define GL_TRANSPOSE_TEXTURE_MATRIX_ARB 0x84E5
1842#define GL_TRIANGLES 0x0004
1843#define GL_TRIANGLES_ADJACENCY 0x000C
1844#define GL_TRIANGLES_ADJACENCY_ARB 0x000C
1845#define GL_TRIANGLE_FAN 0x0006
1846#define GL_TRIANGLE_STRIP 0x0005
1847#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D
1848#define GL_TRIANGLE_STRIP_ADJACENCY_ARB 0x000D
1849#define GL_TRUE 1
1850#define GL_TYPE 0x92FA
1851#define GL_UNDEFINED_VERTEX 0x8260
1852#define GL_UNIFORM 0x92E1
1853#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C
1854#define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA
1855#define GL_UNIFORM_BARRIER_BIT 0x00000004
1856#define GL_UNIFORM_BLOCK 0x92E2
1857#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42
1858#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43
1859#define GL_UNIFORM_BLOCK_BINDING 0x8A3F
1860#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40
1861#define GL_UNIFORM_BLOCK_INDEX 0x8A3A
1862#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41
1863#define GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER 0x90EC
1864#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46
1865#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45
1866#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0
1867#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1
1868#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44
1869#define GL_UNIFORM_BUFFER 0x8A11
1870#define GL_UNIFORM_BUFFER_BINDING 0x8A28
1871#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34
1872#define GL_UNIFORM_BUFFER_SIZE 0x8A2A
1873#define GL_UNIFORM_BUFFER_START 0x8A29
1874#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E
1875#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D
1876#define GL_UNIFORM_NAME_LENGTH 0x8A39
1877#define GL_UNIFORM_OFFSET 0x8A3B
1878#define GL_UNIFORM_SIZE 0x8A38
1879#define GL_UNIFORM_TYPE 0x8A37
1880#define GL_UNPACK_ALIGNMENT 0x0CF5
1881#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129
1882#define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128
1883#define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A
1884#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127
1885#define GL_UNPACK_IMAGE_HEIGHT 0x806E
1886#define GL_UNPACK_LSB_FIRST 0x0CF1
1887#define GL_UNPACK_ROW_LENGTH 0x0CF2
1888#define GL_UNPACK_SKIP_IMAGES 0x806D
1889#define GL_UNPACK_SKIP_PIXELS 0x0CF4
1890#define GL_UNPACK_SKIP_ROWS 0x0CF3
1891#define GL_UNPACK_SWAP_BYTES 0x0CF0
1892#define GL_UNSIGNALED 0x9118
1893#define GL_UNSIGNED_BYTE 0x1401
1894#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362
1895#define GL_UNSIGNED_BYTE_3_3_2 0x8032
1896#define GL_UNSIGNED_INT 0x1405
1897#define GL_UNSIGNED_INT64_ARB 0x140F
1898#define GL_UNSIGNED_INT64_VEC2_ARB 0x8FF5
1899#define GL_UNSIGNED_INT64_VEC3_ARB 0x8FF6
1900#define GL_UNSIGNED_INT64_VEC4_ARB 0x8FF7
1901#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B
1902#define GL_UNSIGNED_INT_10_10_10_2 0x8036
1903#define GL_UNSIGNED_INT_24_8 0x84FA
1904#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
1905#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E
1906#define GL_UNSIGNED_INT_8_8_8_8 0x8035
1907#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
1908#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB
1909#define GL_UNSIGNED_INT_IMAGE_1D 0x9062
1910#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068
1911#define GL_UNSIGNED_INT_IMAGE_2D 0x9063
1912#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069
1913#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B
1914#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C
1915#define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065
1916#define GL_UNSIGNED_INT_IMAGE_3D 0x9064
1917#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067
1918#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066
1919#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A
1920#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1
1921#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6
1922#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2
1923#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7
1924#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A
1925#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D
1926#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5
1927#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3
1928#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8
1929#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4
1930#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F
1931#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900F
1932#define GL_UNSIGNED_INT_VEC2 0x8DC6
1933#define GL_UNSIGNED_INT_VEC3 0x8DC7
1934#define GL_UNSIGNED_INT_VEC4 0x8DC8
1935#define GL_UNSIGNED_NORMALIZED 0x8C17
1936#define GL_UNSIGNED_NORMALIZED_ARB 0x8C17
1937#define GL_UNSIGNED_SHORT 0x1403
1938#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
1939#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
1940#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365
1941#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
1942#define GL_UNSIGNED_SHORT_5_6_5 0x8363
1943#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364
1944#define GL_UPPER_LEFT 0x8CA2
1945#define GL_VALIDATE_STATUS 0x8B83
1946#define GL_VENDOR 0x1F00
1947#define GL_VERSION 0x1F02
1948#define GL_VERTEX_ARRAY 0x8074
1949#define GL_VERTEX_ARRAY_BINDING 0x85B5
1950#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896
1951#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001
1952#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
1953#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F
1954#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE
1955#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB 0x88FE
1956#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
1957#define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622
1958#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD
1959#define GL_VERTEX_ATTRIB_ARRAY_LONG 0x874E
1960#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
1961#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A
1962#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
1963#define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645
1964#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
1965#define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB 0x8623
1966#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
1967#define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624
1968#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
1969#define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB 0x8625
1970#define GL_VERTEX_ATTRIB_BINDING 0x82D4
1971#define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5
1972#define GL_VERTEX_BINDING_BUFFER 0x8F4F
1973#define GL_VERTEX_BINDING_DIVISOR 0x82D6
1974#define GL_VERTEX_BINDING_OFFSET 0x82D7
1975#define GL_VERTEX_BINDING_STRIDE 0x82D8
1976#define GL_VERTEX_PROGRAM_ARB 0x8620
1977#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642
1978#define GL_VERTEX_PROGRAM_POINT_SIZE_ARB 0x8642
1979#define GL_VERTEX_PROGRAM_TWO_SIDE_ARB 0x8643
1980#define GL_VERTEX_SHADER 0x8B31
1981#define GL_VERTEX_SHADER_ARB 0x8B31
1982#define GL_VERTEX_SHADER_BIT 0x00000001
1983#define GL_VERTEX_SHADER_INVOCATIONS 0x82F0
1984#define GL_VERTEX_SHADER_INVOCATIONS_ARB 0x82F0
1985#define GL_VERTEX_SUBROUTINE 0x92E8
1986#define GL_VERTEX_SUBROUTINE_UNIFORM 0x92EE
1987#define GL_VERTEX_TEXTURE 0x829B
1988#define GL_VERTICES_SUBMITTED 0x82EE
1989#define GL_VERTICES_SUBMITTED_ARB 0x82EE
1990#define GL_VIEWPORT 0x0BA2
1991#define GL_VIEWPORT_BOUNDS_RANGE 0x825D
1992#define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F
1993#define GL_VIEWPORT_SUBPIXEL_BITS 0x825C
1994#define GL_VIEW_CLASS_128_BITS 0x82C4
1995#define GL_VIEW_CLASS_16_BITS 0x82CA
1996#define GL_VIEW_CLASS_24_BITS 0x82C9
1997#define GL_VIEW_CLASS_32_BITS 0x82C8
1998#define GL_VIEW_CLASS_48_BITS 0x82C7
1999#define GL_VIEW_CLASS_64_BITS 0x82C6
2000#define GL_VIEW_CLASS_8_BITS 0x82CB
2001#define GL_VIEW_CLASS_96_BITS 0x82C5
2002#define GL_VIEW_CLASS_ASTC_10x10_RGBA 0x9393
2003#define GL_VIEW_CLASS_ASTC_10x5_RGBA 0x9390
2004#define GL_VIEW_CLASS_ASTC_10x6_RGBA 0x9391
2005#define GL_VIEW_CLASS_ASTC_10x8_RGBA 0x9392
2006#define GL_VIEW_CLASS_ASTC_12x10_RGBA 0x9394
2007#define GL_VIEW_CLASS_ASTC_12x12_RGBA 0x9395
2008#define GL_VIEW_CLASS_ASTC_4x4_RGBA 0x9388
2009#define GL_VIEW_CLASS_ASTC_5x4_RGBA 0x9389
2010#define GL_VIEW_CLASS_ASTC_5x5_RGBA 0x938A
2011#define GL_VIEW_CLASS_ASTC_6x5_RGBA 0x938B
2012#define GL_VIEW_CLASS_ASTC_6x6_RGBA 0x938C
2013#define GL_VIEW_CLASS_ASTC_8x5_RGBA 0x938D
2014#define GL_VIEW_CLASS_ASTC_8x6_RGBA 0x938E
2015#define GL_VIEW_CLASS_ASTC_8x8_RGBA 0x938F
2016#define GL_VIEW_CLASS_BPTC_FLOAT 0x82D3
2017#define GL_VIEW_CLASS_BPTC_UNORM 0x82D2
2018#define GL_VIEW_CLASS_EAC_R11 0x9383
2019#define GL_VIEW_CLASS_EAC_RG11 0x9384
2020#define GL_VIEW_CLASS_ETC2_EAC_RGBA 0x9387
2021#define GL_VIEW_CLASS_ETC2_RGB 0x9385
2022#define GL_VIEW_CLASS_ETC2_RGBA 0x9386
2023#define GL_VIEW_CLASS_RGTC1_RED 0x82D0
2024#define GL_VIEW_CLASS_RGTC2_RG 0x82D1
2025#define GL_VIEW_CLASS_S3TC_DXT1_RGB 0x82CC
2026#define GL_VIEW_CLASS_S3TC_DXT1_RGBA 0x82CD
2027#define GL_VIEW_CLASS_S3TC_DXT3_RGBA 0x82CE
2028#define GL_VIEW_CLASS_S3TC_DXT5_RGBA 0x82CF
2029#define GL_VIEW_COMPATIBILITY_CLASS 0x82B6
2030#define GL_WAIT_FAILED 0x911D
2031#define GL_WEIGHTED_AVERAGE_ARB 0x9367
2032#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E
2033#define GL_WRITE_ONLY 0x88B9
2034#define GL_WRITE_ONLY_ARB 0x88B9
2035#define GL_XOR 0x1506
2036#define GL_ZERO 0
2037
2038
2039#ifndef __khrplatform_h_
2040#define __khrplatform_h_
2041
2042/*
2043** Copyright (c) 2008-2018 The Khronos Group Inc.
2044**
2045** Permission is hereby granted, free of charge, to any person obtaining a
2046** copy of this software and/or associated documentation files (the
2047** "Materials"), to deal in the Materials without restriction, including
2048** without limitation the rights to use, copy, modify, merge, publish,
2049** distribute, sublicense, and/or sell copies of the Materials, and to
2050** permit persons to whom the Materials are furnished to do so, subject to
2051** the following conditions:
2052**
2053** The above copyright notice and this permission notice shall be included
2054** in all copies or substantial portions of the Materials.
2055**
2056** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2057** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2058** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
2059** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
2060** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
2061** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
2062** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
2063*/
2064
2065/* Khronos platform-specific types and definitions.
2066 *
2067 * The master copy of khrplatform.h is maintained in the Khronos EGL
2068 * Registry repository at https://github.com/KhronosGroup/EGL-Registry
2069 * The last semantic modification to khrplatform.h was at commit ID:
2070 * 67a3e0864c2d75ea5287b9f3d2eb74a745936692
2071 *
2072 * Adopters may modify this file to suit their platform. Adopters are
2073 * encouraged to submit platform specific modifications to the Khronos
2074 * group so that they can be included in future versions of this file.
2075 * Please submit changes by filing pull requests or issues on
2076 * the EGL Registry repository linked above.
2077 *
2078 *
2079 * See the Implementer's Guidelines for information about where this file
2080 * should be located on your system and for more details of its use:
2081 * http://www.khronos.org/registry/implementers_guide.pdf
2082 *
2083 * This file should be included as
2084 * #include <KHR/khrplatform.h>
2085 * by Khronos client API header files that use its types and defines.
2086 *
2087 * The types in khrplatform.h should only be used to define API-specific types.
2088 *
2089 * Types defined in khrplatform.h:
2090 * khronos_int8_t signed 8 bit
2091 * khronos_uint8_t unsigned 8 bit
2092 * khronos_int16_t signed 16 bit
2093 * khronos_uint16_t unsigned 16 bit
2094 * khronos_int32_t signed 32 bit
2095 * khronos_uint32_t unsigned 32 bit
2096 * khronos_int64_t signed 64 bit
2097 * khronos_uint64_t unsigned 64 bit
2098 * khronos_intptr_t signed same number of bits as a pointer
2099 * khronos_uintptr_t unsigned same number of bits as a pointer
2100 * khronos_ssize_t signed size
2101 * khronos_usize_t unsigned size
2102 * khronos_float_t signed 32 bit floating point
2103 * khronos_time_ns_t unsigned 64 bit time in nanoseconds
2104 * khronos_utime_nanoseconds_t unsigned time interval or absolute time in
2105 * nanoseconds
2106 * khronos_stime_nanoseconds_t signed time interval in nanoseconds
2107 * khronos_boolean_enum_t enumerated boolean type. This should
2108 * only be used as a base type when a client API's boolean type is
2109 * an enum. Client APIs which use an integer or other type for
2110 * booleans cannot use this as the base type for their boolean.
2111 *
2112 * Tokens defined in khrplatform.h:
2113 *
2114 * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
2115 *
2116 * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
2117 * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
2118 *
2119 * Calling convention macros defined in this file:
2120 * KHRONOS_APICALL
2121 * KHRONOS_GLAD_API_PTR
2122 * KHRONOS_APIATTRIBUTES
2123 *
2124 * These may be used in function prototypes as:
2125 *
2126 * KHRONOS_APICALL void KHRONOS_GLAD_API_PTR funcname(
2127 * int arg1,
2128 * int arg2) KHRONOS_APIATTRIBUTES;
2129 */
2130
2131#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
2132# define KHRONOS_STATIC 1
2133#endif
2134
2135/*-------------------------------------------------------------------------
2136 * Definition of KHRONOS_APICALL
2137 *-------------------------------------------------------------------------
2138 * This precedes the return type of the function in the function prototype.
2139 */
2140#if defined(KHRONOS_STATIC)
2141 /* If the preprocessor constant KHRONOS_STATIC is defined, make the
2142 * header compatible with static linking. */
2143# define KHRONOS_APICALL
2144#elif defined(_WIN32)
2145# define KHRONOS_APICALL __declspec(dllimport)
2146#elif defined (__SYMBIAN32__)
2147# define KHRONOS_APICALL IMPORT_C
2148#elif defined(__ANDROID__)
2149# define KHRONOS_APICALL __attribute__((visibility("default")))
2150#else
2151