mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-22 00:06:59 +02:00
Compare commits
65 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9634bedb5b | |||
| b113d498a5 | |||
| 1078dc292a | |||
| b33eb2ea4f | |||
| a6a7a76e6f | |||
| 20c9f7fe0a | |||
| ce05296055 | |||
| dec6c16539 | |||
| 13d161bc8d | |||
| 347321b27c | |||
| da94cf2bc6 | |||
| 8e6283aa31 | |||
| d0b98eee6b | |||
| 74912d525b | |||
| a551f0e70b | |||
| 7dae981ad5 | |||
| 88776cedb7 | |||
| e00cee2af1 | |||
| 5ef2e1ec57 | |||
| ee8a65bed9 | |||
| 44b847fbf8 | |||
| 5f3de510b2 | |||
| 53116ad6da | |||
| b83869eb09 | |||
| bedfd053cb | |||
| 32cc6d53cd | |||
| bd26454c26 | |||
| d791c16d8d | |||
| 8c4535c6c5 | |||
| 27d2d6ac87 | |||
| 919a01ae4a | |||
| 065e6eadb5 | |||
| 962d11b4ce | |||
| b62249ceaf | |||
| 525b04db04 | |||
| e93e1dbba1 | |||
| 111d620c63 | |||
| 3b4e87848b | |||
| 35acd7a65b | |||
| 92fb865387 | |||
| c44ec3f46a | |||
| 8c3b213a7c | |||
| 88797e9dee | |||
| ad85d0c3c4 | |||
| 364844231d | |||
| 9ea38e9f3a | |||
| af19bdb6ff | |||
| f513f462df | |||
| 8c1dc255db | |||
| dbf8e114f9 | |||
| 6d65be5e0e | |||
| 6a895501cf | |||
| 787318fd8f | |||
| 4a8467852a | |||
| 80cf7b2deb | |||
| 2db0984566 | |||
| 669ed3e844 | |||
| 81410769ae | |||
| ffe558437f | |||
| 089f041120 | |||
| 2e02046c6d | |||
| b22a0cbdb1 | |||
| b3c6bcec39 | |||
| ed2c5270c8 | |||
| 3dfcefc75b |
@@ -0,0 +1,4 @@
|
||||
I deal with all security related issues publicly and transparently, and it can sometimes take a while before I
|
||||
get a chance to address it. If this is an issue for you, you need to use another library. The fastest way to get
|
||||
a bug fixed is to submit a pull request, but if this is impractical for you please post a ticket to the public
|
||||
GitHub issue tracker.
|
||||
+23
@@ -1,3 +1,26 @@
|
||||
v0.11.25 - 2026-03-04
|
||||
=====================
|
||||
* Bug fixes to the WAV decoder.
|
||||
* Fixed warnings with the Emscripten build relating to the renaming of of `__EMSCRIPTEN_major/minor/tiny__` macros.
|
||||
* Win32: Fixed an error with runtime linking on the UWP build. This is actually a non issue in practice because it would require miniaudio to pass in a DLL name of longer than 2048 characters which it never does.
|
||||
|
||||
|
||||
v0.11.24 - 2026-01-17
|
||||
=====================
|
||||
* Fixed a possible glitch when processing the audio of a `ma_sound` when doing resampling.
|
||||
* Fixed a possible crash in the node graph relating to scheduled starts and stops.
|
||||
* Fixed a bug where MA_NO_DECODING would disable the WAV encoder.
|
||||
* Fixed a pthread compatibility issue, particularly with Android.
|
||||
* Fixed a possible crash in the resource manager.
|
||||
* Fixed a possible double-uninit error when a decoder fails to initialize.
|
||||
* Fixed a compilation error with the MSVC Aarch64 build.
|
||||
* Addressed a few errors found through static analysis, particularly around possible null pointer dereferences.
|
||||
* `ma_sound_is_playing()` will now correctly return false when called from inside the end callback of a sound.
|
||||
* Miscellaneous compiler compatibility and warning fixes.
|
||||
* PulseAudio: Fix a resource leak when a context fails to connect.
|
||||
* Web: Fixed an error when uninitializing a context.
|
||||
|
||||
|
||||
v0.11.23 - 2025-09-11
|
||||
=====================
|
||||
* Fixed an error in `ma_channel_map_to_string()` where the output string is not null terminated correctly.
|
||||
|
||||
+18
-6
@@ -70,7 +70,7 @@ option(MINIAUDIO_NO_NEON "Disable NEON optimizations"
|
||||
option(MINIAUDIO_NO_RUNTIME_LINKING "Disable runtime linking" OFF)
|
||||
option(MINIAUDIO_USE_STDINT "Use <stdint.h> for sized types" OFF)
|
||||
option(MINIAUDIO_DEBUG_OUTPUT "Enable stdout debug output" OFF)
|
||||
|
||||
option(MINIAUDIO_INSTALL "Enable installation targets" ON)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
@@ -508,7 +508,9 @@ add_library(miniaudio
|
||||
)
|
||||
|
||||
list(APPEND LIBS_TO_INSTALL miniaudio)
|
||||
install(FILES miniaudio.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/miniaudio)
|
||||
if(MINIAUDIO_INSTALL)
|
||||
install(FILES miniaudio.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/miniaudio)
|
||||
endif()
|
||||
|
||||
target_include_directories(miniaudio PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_compile_options (miniaudio PRIVATE ${COMPILE_OPTIONS})
|
||||
@@ -534,11 +536,14 @@ if(HAS_LIBVORBIS)
|
||||
)
|
||||
|
||||
list(APPEND LIBS_TO_INSTALL miniaudio_libvorbis)
|
||||
if(MINIAUDIO_INSTALL)
|
||||
install(FILES extras/decoders/libvorbis/miniaudio_libvorbis.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/miniaudio/extras/decoders/libvorbis)
|
||||
endif()
|
||||
|
||||
target_compile_options (miniaudio_libvorbis PRIVATE ${COMPILE_OPTIONS})
|
||||
target_compile_definitions(miniaudio_libvorbis PRIVATE ${COMPILE_DEFINES})
|
||||
target_link_libraries (miniaudio_libvorbis PRIVATE libvorbis_interface)
|
||||
target_include_directories(miniaudio_libvorbis PUBLIC extras/decoders/libvorbis/)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -562,11 +567,14 @@ if(HAS_LIBOPUS)
|
||||
|
||||
|
||||
list(APPEND LIBS_TO_INSTALL miniaudio_libopus)
|
||||
if(MINIAUDIO_INSTALL)
|
||||
install(FILES extras/decoders/libopus/miniaudio_libopus.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/miniaudio/extras/decoders/libopus)
|
||||
endif()
|
||||
|
||||
target_compile_options (miniaudio_libopus PRIVATE ${COMPILE_OPTIONS})
|
||||
target_compile_definitions(miniaudio_libopus PRIVATE ${COMPILE_DEFINES})
|
||||
target_link_libraries (miniaudio_libopus PRIVATE libopus_interface)
|
||||
target_include_directories(miniaudio_libopus PUBLIC extras/decoders/libopus/)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -581,7 +589,9 @@ if (NOT MINIAUDIO_NO_EXTRA_NODES)
|
||||
|
||||
list(APPEND libs miniaudio_${name}_node)
|
||||
set(LIBS_TO_INSTALL "${libs}" PARENT_SCOPE) # without PARENT_SCOPE, any changes are lost
|
||||
if(MINIAUDIO_INSTALL)
|
||||
install(FILES extras/nodes/ma_${name}_node/ma_${name}_node.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/miniaudio/extras/nodes/ma_${name}_node)
|
||||
endif()
|
||||
|
||||
target_include_directories(miniaudio_${name}_node PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/extras/nodes/ma_${name}_node)
|
||||
target_compile_options (miniaudio_${name}_node PRIVATE ${COMPILE_OPTIONS})
|
||||
@@ -856,11 +866,13 @@ string(JOIN " " MINIAUDIO_PC_CFLAGS ${COMPILE_DEFINES})
|
||||
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/miniaudio.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/miniaudio.pc" @ONLY)
|
||||
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/miniaudio.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||
if(MINIAUDIO_INSTALL)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/miniaudio.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||
|
||||
message(STATUS "Library list: ${LIBS_TO_INSTALL}")
|
||||
install(TARGETS ${LIBS_TO_INSTALL}
|
||||
message(STATUS "Library list: ${LIBS_TO_INSTALL}")
|
||||
install(TARGETS ${LIBS_TO_INSTALL}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -205,10 +205,7 @@ Backends
|
||||
|
||||
Security
|
||||
========
|
||||
I deal with all security related issues publicly and transparently, and it can sometimes take a while before I
|
||||
get a chance to address it. If this is an issue for you, you need to use another library. The fastest way to get
|
||||
a bug fixed is to submit a pull request, but if this is impractical for you please post a ticket to the public
|
||||
GitHub issue tracker.
|
||||
See the miniaudio [security policy](.github/SECURITY.md).
|
||||
|
||||
|
||||
License
|
||||
|
||||
Vendored
+670
-137
File diff suppressed because it is too large
Load Diff
Vendored
+266
-36
@@ -740,12 +740,6 @@ init
|
||||
uninit
|
||||
This is where you should do any cleanup. Do not close the stream here.
|
||||
|
||||
ioctl
|
||||
This function is optional. You can use this to implement custom IO control commands. Return
|
||||
`FS_INVALID_OPERATION` if the command is not recognized. The format of the `pArg` parameter is
|
||||
command specific. If the backend does not need to implement this function, it can be left as
|
||||
`NULL` or return `FS_NOT_IMPLEMENTED`.
|
||||
|
||||
remove
|
||||
This function is used to delete a file or directory. This is not recursive. If the path is
|
||||
a directory, the backend should return an error if it is not empty. Backends do not need to
|
||||
@@ -939,6 +933,14 @@ see some random tags and stuff in this file. These are just used for doing a dum
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* BEG fs_platform_detection.c */
|
||||
#if defined(_WIN32)
|
||||
#define FS_WIN32
|
||||
#else
|
||||
#define FS_POSIX
|
||||
#endif
|
||||
/* END fs_platform_detection.c */
|
||||
|
||||
/* BEG fs_compiler_compat.h */
|
||||
#include <stddef.h> /* For size_t. */
|
||||
#include <stdarg.h> /* For va_list. */
|
||||
@@ -1060,6 +1062,75 @@ typedef unsigned int fs_bool32;
|
||||
/* END fs_compiler_compat.h */
|
||||
|
||||
|
||||
/* BEG fs_thread_basic_types.h */
|
||||
#if defined(FS_POSIX)
|
||||
#ifndef FS_USE_PTHREAD
|
||||
#define FS_USE_PTHREAD
|
||||
#endif
|
||||
|
||||
#ifndef FS_NO_PTHREAD_IN_HEADER
|
||||
#include <pthread.h>
|
||||
typedef pthread_t fs_pthread_t;
|
||||
typedef pthread_mutex_t fs_pthread_mutex_t;
|
||||
#else
|
||||
typedef fs_uintptr fs_pthread_t;
|
||||
typedef union fs_pthread_mutex_t { char __data[40]; fs_uint64 __alignment; } fs_pthread_mutex_t;
|
||||
#endif
|
||||
#endif
|
||||
/* END fs_thread_basic_types.h */
|
||||
|
||||
|
||||
/* BEG fs_thread_mtx.h */
|
||||
#if defined(FS_WIN32)
|
||||
typedef struct
|
||||
{
|
||||
void* handle; /* HANDLE, CreateMutex(), CreateEvent() */
|
||||
int type;
|
||||
} fs_mtx;
|
||||
#else
|
||||
/*
|
||||
We may need to force the use of a manual recursive mutex which will happen when compiling
|
||||
on very old compilers, or with `-std=c89`.
|
||||
*/
|
||||
|
||||
/* If __STDC_VERSION__ is not defined it means we're compiling in C89 mode. */
|
||||
#if !defined(FS_USE_MANUAL_RECURSIVE_MUTEX) && !defined(__STDC_VERSION__)
|
||||
#define FS_USE_MANUAL_RECURSIVE_MUTEX
|
||||
#endif
|
||||
|
||||
/* This is for checking if PTHREAD_MUTEX_RECURSIVE is available. */
|
||||
#if !defined(FS_USE_MANUAL_RECURSIVE_MUTEX) && (!defined(__USE_UNIX98) && !defined(__USE_XOPEN2K8))
|
||||
#define FS_USE_MANUAL_RECURSIVE_MUTEX
|
||||
#endif
|
||||
|
||||
#ifdef FS_USE_MANUAL_RECURSIVE_MUTEX
|
||||
typedef struct
|
||||
{
|
||||
fs_pthread_mutex_t mutex; /* The underlying pthread mutex. */
|
||||
fs_pthread_mutex_t guard; /* Guard for metadata (owner and recursionCount). */
|
||||
fs_pthread_t owner;
|
||||
int recursionCount;
|
||||
int type;
|
||||
} fs_mtx;
|
||||
#else
|
||||
typedef fs_pthread_mutex_t fs_mtx;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
fs_mtx_plain = 0x00000000,
|
||||
fs_mtx_timed = 0x00000001,
|
||||
fs_mtx_recursive = 0x00000002
|
||||
};
|
||||
|
||||
FS_API int fs_mtx_init(fs_mtx* mutex, int type);
|
||||
FS_API void fs_mtx_destroy(fs_mtx* mutex);
|
||||
FS_API int fs_mtx_lock(fs_mtx* mutex);
|
||||
FS_API int fs_mtx_unlock(fs_mtx* mutex);
|
||||
/* END fs_thread_mtx.h */
|
||||
|
||||
|
||||
/* BEG fs_result.h */
|
||||
typedef enum
|
||||
{
|
||||
@@ -1125,7 +1196,7 @@ typedef enum
|
||||
FS_HAS_MORE_OUTPUT = 102 /* Some stream has more output data to be read, but there's not enough room in the output buffer. */
|
||||
} fs_result;
|
||||
|
||||
FS_API const char* fs_result_to_string(fs_result result);
|
||||
FS_API const char* fs_result_description(fs_result result);
|
||||
/* END fs_result.h */
|
||||
|
||||
|
||||
@@ -1160,6 +1231,7 @@ The stream vtable can support both reading and writing, but it doesn't need to s
|
||||
the same time. If one is not supported, simply leave the relevant `read` or `write` callback as
|
||||
`NULL`, or have them return FS_NOT_IMPLEMENTED.
|
||||
*/
|
||||
|
||||
typedef enum fs_seek_origin
|
||||
{
|
||||
FS_SEEK_SET = 0,
|
||||
@@ -1229,6 +1301,7 @@ appended to the end of the data.
|
||||
For flexiblity in case the backend does not support cursor retrieval or positioning, the data will be read
|
||||
in fixed sized chunks.
|
||||
*/
|
||||
|
||||
typedef enum fs_format
|
||||
{
|
||||
FS_FORMAT_TEXT,
|
||||
@@ -1443,6 +1516,42 @@ struct fs_iterator
|
||||
fs_file_info info;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Configuration structure for fs objects.
|
||||
|
||||
Members
|
||||
-------
|
||||
pBackend
|
||||
The backend to use. If NULL, the standard file system backend will be used.
|
||||
|
||||
pBackendConfig
|
||||
A pointer to a backend-specific configuration structure. This is passed directly to the
|
||||
backend's init function. The documentation for your backend will tell you how to use this. Most
|
||||
backends will allow you to set this to NULL.
|
||||
|
||||
pStream
|
||||
A stream to use for archive backends. This is required for any file-backed backend, such as ZIP
|
||||
archives. If the backend does not need a stream, this can be NULL.
|
||||
|
||||
pArchiveTypes
|
||||
An array of archive types to register. This can be NULL if no archive types are to be
|
||||
registered. Archive types are mapped to file extensions. See `fs_archive_type` for more
|
||||
information.
|
||||
|
||||
archiveTypeCount
|
||||
The number of archive types in the `pArchiveTypes` array. Set this to 0 if `pArchiveTypes` is
|
||||
NULL.
|
||||
|
||||
onRefCountChanged
|
||||
A callback that is fired when the reference count of a fs object changes.
|
||||
|
||||
pRefCountChangedUserData
|
||||
User data that is passed to the `onRefCountChanged` callback.
|
||||
|
||||
pAllocationCallbacks
|
||||
Custom allocation callbacks. If NULL, the standard malloc/realloc/free functions will be used.
|
||||
*/
|
||||
struct fs_config
|
||||
{
|
||||
const fs_backend* pBackend;
|
||||
@@ -1464,7 +1573,6 @@ struct fs_backend
|
||||
size_t (* alloc_size )(const void* pBackendConfig);
|
||||
fs_result (* init )(fs* pFS, const void* pBackendConfig, fs_stream* pStream); /* Return 0 on success or an errno result code on error. pBackendConfig is a pointer to a backend-specific struct. The documentation for your backend will tell you how to use this. You can usually pass in NULL for this. */
|
||||
void (* uninit )(fs* pFS);
|
||||
fs_result (* ioctl )(fs* pFS, int op, void* pArg); /* Optional. */
|
||||
fs_result (* remove )(fs* pFS, const char* pFilePath);
|
||||
fs_result (* rename )(fs* pFS, const char* pOldPath, const char* pNewPath); /* Return FS_DIFFERENT_DEVICE if the old and new paths are on different devices and would require a copy. */
|
||||
fs_result (* mkdir )(fs* pFS, const char* pPath); /* This is not recursive. Return FS_ALREADY_EXISTS if directory already exists. Return FS_DOES_NOT_EXIST if a parent directory does not exist. */
|
||||
@@ -1661,34 +1769,6 @@ fs_init()
|
||||
FS_API void fs_uninit(fs* pFS);
|
||||
|
||||
|
||||
/*
|
||||
Performs a control operation on the file system.
|
||||
|
||||
This is backend-specific. Check the documentation for the backend you are using to see what
|
||||
operations are supported.
|
||||
|
||||
|
||||
Parameters
|
||||
----------
|
||||
pFS : (in)
|
||||
A pointer to the file system object. Must not be NULL.
|
||||
|
||||
op : (in)
|
||||
The operation to perform. This is backend-specific.
|
||||
|
||||
pArg : (in, optional)
|
||||
An optional pointer to an argument struct. This is backend-specific. Can be NULL if the
|
||||
operation does not require any arguments.
|
||||
|
||||
|
||||
Return Value
|
||||
------------
|
||||
Returns FS_SUCCESS on success; any other result code otherwise. May return FS_NOT_IMPLEMENTED if
|
||||
the operation is not supported by the backend.
|
||||
*/
|
||||
FS_API fs_result fs_ioctl(fs* pFS, int op, void* pArg);
|
||||
|
||||
|
||||
/*
|
||||
Removes a file or empty directory.
|
||||
|
||||
@@ -3291,6 +3371,154 @@ FS_API fs_result fs_file_open_and_read(fs* pFS, const char* pFilePath, fs_format
|
||||
FS_API fs_result fs_file_open_and_write(fs* pFS, const char* pFilePath, const void* pData, size_t dataSize);
|
||||
|
||||
|
||||
/*
|
||||
Serializes a file system subdirectory to a stream.
|
||||
|
||||
This function recursively serializes all files and directories within the specified directory
|
||||
to a binary stream. The serialized data can later be restored using `fs_deserialize()`.
|
||||
|
||||
The directory parameter specifies which directory to serialize. This function is built on top of
|
||||
standard file iteration functions, i.e. `fs_first()`, `fs_next()`. The directory and options all
|
||||
work the same way as they do for `fs_first()`.
|
||||
|
||||
It is possible for serialization to fail partway through, in which case the stream will contain
|
||||
partial data. It is the caller's responsibility to handle this case appropriately.
|
||||
|
||||
When calculating offsets, it will use `fs_stream_tell()` to get the current position in the stream.
|
||||
Keep this in mind if you are appending this to the end of an existing stream. This may or may not
|
||||
be useful to you depending on your use case.
|
||||
|
||||
The format is designed to be appendable to existing payloads using tools like `cat`. Offsets are
|
||||
stored relative to the end of the archive to support this use case. The Base Offset field in the
|
||||
tail specifies where file data begins relative to the end of the stream, and will always be a
|
||||
negative number. Each file's offset is then relative to this base offset. To seek to a file's data,
|
||||
you would add the file's offset to the base offset and then seek by that amount relative to the end
|
||||
of the stream.
|
||||
|
||||
Below is the format:
|
||||
|
||||
|: MAIN STRUCTURE :|
|
||||
|------------------------------------------------|
|
||||
| n | File Data |
|
||||
|------|-----------------------------------------|
|
||||
| n | TOC Entries |
|
||||
|------|-----------------------------------------|
|
||||
| 8 | 'FSSRLZ1\0' |
|
||||
| 8 | Base Offset (negative, relative to end) |
|
||||
| 8 | TOC Offset (relative to Base Offset) |
|
||||
| 4 | TOC Entry Count |
|
||||
| 4 | Reserved (set to zero) |
|
||||
|
||||
|
||||
|: TOC ENTRY :|
|
||||
|------------------------------------------------|
|
||||
| 4 | File Flags |
|
||||
| 4 | File Path Length |
|
||||
| n | File Path |
|
||||
| 1 | '\0' (Null Terminator) |
|
||||
| n | Padding to 8-byte alignment |
|
||||
| 8 | File Size |
|
||||
| 8 | File Offset (local, relative) |
|
||||
|
||||
|
||||
|: FILE FLAGS :|
|
||||
|------------------------------------------------|
|
||||
| 0x1 | Directory |
|
||||
|
||||
|
||||
Notes:
|
||||
- The signature is located at the end of the stream. To parse, seek to the last 32 bytes, read
|
||||
the signature, base offset, TOC offset and entry count, then calculate the absolute TOC offset
|
||||
as Base Offset + TOC Offset and seek to that position, relative to the end, to read the TOC.
|
||||
The base offset is always negative.
|
||||
- Directories should be explicitly listed in the TOC, and also have the "Directory" flag set.
|
||||
- Directories must be listed before any files that are contained within them.
|
||||
- File Offset and TOC Offset are both local offsets relative to the Base Offset position. Sum
|
||||
the offsets with the base offset, and then seek relative to the end.
|
||||
- The Base Offset is relative to the end of the archive (negative value).
|
||||
- File data is aligned to 8-byte boundaries.
|
||||
- All multi-byte values are little-endian.
|
||||
- File paths are stored using UTF-8 encoding.
|
||||
- To calculate the padding between the null terminator and the next 8-byte aligned offset, round
|
||||
the length of the file path plus one (for the null terminator) up to the next multiple of 8,
|
||||
then subtract the length of the file path plus one.
|
||||
|
||||
|
||||
Parameters
|
||||
----------
|
||||
pFS : (in)
|
||||
A pointer to the file system object. Must not be NULL.
|
||||
|
||||
pDirectoryPath : (in, optional)
|
||||
The path to the directory to serialize.
|
||||
|
||||
options : (in)
|
||||
Options for the serialization operation. These are passed in directly to `fs_first()` and
|
||||
therefore have the same meaning. See `fs_first()` for details. These will also be passed into
|
||||
`fs_file_open()` when opening files, combined with `FS_READ`.
|
||||
|
||||
pOutputStream : (in)
|
||||
A pointer to the output stream where the serialized data will be written. Must not be NULL.
|
||||
|
||||
|
||||
Return Value
|
||||
------------
|
||||
Returns FS_SUCCESS on success; any other result code otherwise.
|
||||
|
||||
|
||||
See Also
|
||||
--------
|
||||
fs_deserialize()
|
||||
fs_first()
|
||||
*/
|
||||
FS_API fs_result fs_serialize(fs* pFS, const char* pDirectoryPath, int options, fs_stream* pOutputStream);
|
||||
|
||||
/*
|
||||
Deserializes file system data from a stream.
|
||||
|
||||
This function reads serialized file system data from a stream and recreates the files and
|
||||
directories in the specified subdirectory. The format of the data must match that produced by
|
||||
`fs_serialize()`.
|
||||
|
||||
The subdirectory parameter specifies where to restore the serialized data. If NULL or empty, the
|
||||
data is restored to the file system root. The path is relative to the file system root.
|
||||
|
||||
Existing files with the same name will be overwritten during deserialization. If the output
|
||||
directory already exists, it will not emptied before restoring the data.
|
||||
|
||||
This function will not attempt to clean up any partially restored data if an error occurs during
|
||||
the process.
|
||||
|
||||
|
||||
Parameters
|
||||
----------
|
||||
pFS : (in)
|
||||
A pointer to the file system object. Must not be NULL.
|
||||
|
||||
pSubdirectoryPath : (in, optional)
|
||||
The path to the subdirectory where the data should be restored. Can be NULL or empty to
|
||||
restore to the filesystem root. The path should use forward slashes ('/') as separators.
|
||||
|
||||
options : (in)
|
||||
Options for the deserialization operation. These will be passed into `fs_file_open()` when
|
||||
creating files. See `fs_file_open()` for details.
|
||||
|
||||
pInputStream : (in)
|
||||
A pointer to the input stream containing the serialized data. Must not be NULL.
|
||||
|
||||
|
||||
Return Value
|
||||
------------
|
||||
Returns FS_SUCCESS on success; any other result code otherwise.
|
||||
|
||||
|
||||
See Also
|
||||
--------
|
||||
fs_serialize()
|
||||
*/
|
||||
FS_API fs_result fs_deserialize(fs* pFS, const char* pDirectoryPath, int options, fs_stream* pInputStream);
|
||||
|
||||
|
||||
/* BEG fs_backend_posix.h */
|
||||
extern const fs_backend* FS_BACKEND_POSIX;
|
||||
/* END fs_backend_posix.h */
|
||||
@@ -3417,6 +3645,7 @@ read and write from different locations from the same fs_memory_stream object, y
|
||||
seek before doing your read or write. You cannot read and write at the same time across
|
||||
multiple threads for the same fs_memory_stream object.
|
||||
*/
|
||||
|
||||
typedef struct fs_memory_stream fs_memory_stream;
|
||||
|
||||
struct fs_memory_stream
|
||||
@@ -3460,6 +3689,7 @@ FS_API void* fs_sorted_search(const void* pKey, const void* pList, size_t count,
|
||||
|
||||
FS_API int fs_strncmp(const char* str1, const char* str2, size_t maxLen);
|
||||
FS_API int fs_strnicmp(const char* str1, const char* str2, size_t count);
|
||||
FS_API int fs_strncat_s(char* dst, size_t dstCap, const char* src, size_t count);
|
||||
/* END fs_utils.h */
|
||||
|
||||
|
||||
|
||||
+503
-302
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file.
|
||||
miniaudio - v0.11.23 - 2025-09-11
|
||||
miniaudio - v0.11.25 - 2026-03-04
|
||||
|
||||
David Reid - mackron@gmail.com
|
||||
|
||||
@@ -20,7 +20,7 @@ extern "C" {
|
||||
|
||||
#define MA_VERSION_MAJOR 0
|
||||
#define MA_VERSION_MINOR 11
|
||||
#define MA_VERSION_REVISION 23
|
||||
#define MA_VERSION_REVISION 25
|
||||
#define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION)
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
@@ -131,7 +131,7 @@ typedef ma_uint16 wchar_t;
|
||||
|
||||
|
||||
/* Platform/backend detection. */
|
||||
#if defined(_WIN32) || defined(__COSMOPOLITAN__)
|
||||
#if defined(_WIN32)
|
||||
#define MA_WIN32
|
||||
#if defined(MA_FORCE_UWP) || (defined(WINAPI_FAMILY) && ((defined(WINAPI_FAMILY_PC_APP) && WINAPI_FAMILY == WINAPI_FAMILY_PC_APP) || (defined(WINAPI_FAMILY_PHONE_APP) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)))
|
||||
#define MA_WIN32_UWP
|
||||
@@ -455,9 +455,13 @@ typedef enum
|
||||
MA_CHANNEL_AUX_29 = 49,
|
||||
MA_CHANNEL_AUX_30 = 50,
|
||||
MA_CHANNEL_AUX_31 = 51,
|
||||
|
||||
/* Count. */
|
||||
MA_CHANNEL_POSITION_COUNT,
|
||||
|
||||
/* Aliases. */
|
||||
MA_CHANNEL_LEFT = MA_CHANNEL_FRONT_LEFT,
|
||||
MA_CHANNEL_RIGHT = MA_CHANNEL_FRONT_RIGHT,
|
||||
MA_CHANNEL_POSITION_COUNT = (MA_CHANNEL_AUX_31 + 1)
|
||||
} _ma_channel_position; /* Do not use `_ma_channel_position` directly. Use `ma_channel` instead. */
|
||||
|
||||
typedef enum
|
||||
@@ -2877,16 +2881,12 @@ This section contains the APIs for device playback and capture. Here is where yo
|
||||
#if defined(MA_WIN32_DESKTOP) /* DirectSound and WinMM backends are only supported on desktops. */
|
||||
#define MA_SUPPORT_DSOUND
|
||||
#define MA_SUPPORT_WINMM
|
||||
|
||||
/* Don't enable JACK here if compiling with Cosmopolitan. It'll be enabled in the Linux section below. */
|
||||
#if !defined(__COSMOPOLITAN__)
|
||||
#define MA_SUPPORT_JACK /* JACK is technically supported on Windows, but I don't know how many people use it in practice... */
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#if defined(MA_UNIX) && !defined(MA_ORBIS) && !defined(MA_PROSPERO)
|
||||
#if defined(MA_LINUX)
|
||||
#if !defined(MA_ANDROID) && !defined(__COSMOPOLITAN__) /* ALSA is not supported on Android. */
|
||||
#if !defined(MA_ANDROID) && !defined(MA_EMSCRIPTEN) /* ALSA is not supported on Android. */
|
||||
#define MA_SUPPORT_ALSA
|
||||
#endif
|
||||
#endif
|
||||
@@ -5948,7 +5948,7 @@ Parameters
|
||||
----------
|
||||
pBackends (out, optional)
|
||||
A pointer to the buffer that will receive the enabled backends. Set to NULL to retrieve the backend count. Setting
|
||||
the capacity of the buffer to `MA_BUFFER_COUNT` will guarantee it's large enough for all backends.
|
||||
the capacity of the buffer to `MA_BACKEND_COUNT` will guarantee it's large enough for all backends.
|
||||
|
||||
backendCap (in)
|
||||
The capacity of the `pBackends` buffer.
|
||||
@@ -6793,6 +6793,7 @@ typedef struct
|
||||
ma_decoding_backend_vtable** ppCustomDecodingBackendVTables;
|
||||
ma_uint32 customDecodingBackendCount;
|
||||
void* pCustomDecodingBackendUserData;
|
||||
ma_resampler_config resampling;
|
||||
} ma_resource_manager_config;
|
||||
|
||||
MA_API ma_resource_manager_config ma_resource_manager_config_init(void);
|
||||
@@ -7120,6 +7121,7 @@ MA_API ma_result ma_node_graph_read_pcm_frames(ma_node_graph* pNodeGraph, void*
|
||||
MA_API ma_uint32 ma_node_graph_get_channels(const ma_node_graph* pNodeGraph);
|
||||
MA_API ma_uint64 ma_node_graph_get_time(const ma_node_graph* pNodeGraph);
|
||||
MA_API ma_result ma_node_graph_set_time(ma_node_graph* pNodeGraph, ma_uint64 globalTime);
|
||||
MA_API ma_uint32 ma_node_graph_get_processing_size_in_frames(const ma_node_graph* pNodeGraph);
|
||||
|
||||
|
||||
|
||||
@@ -7427,6 +7429,7 @@ typedef struct
|
||||
ma_bool8 isPitchDisabled; /* Pitching can be explicitly disabled with MA_SOUND_FLAG_NO_PITCH to optimize processing. */
|
||||
ma_bool8 isSpatializationDisabled; /* Spatialization can be explicitly disabled with MA_SOUND_FLAG_NO_SPATIALIZATION. */
|
||||
ma_uint8 pinnedListenerIndex; /* The index of the listener this node should always use for spatialization. If set to MA_LISTENER_INDEX_CLOSEST the engine will use the closest listener. */
|
||||
ma_resampler_config resampling;
|
||||
} ma_engine_node_config;
|
||||
|
||||
MA_API ma_engine_node_config ma_engine_node_config_init(ma_engine* pEngine, ma_engine_node_type type, ma_uint32 flags);
|
||||
@@ -7441,7 +7444,7 @@ typedef struct
|
||||
ma_uint32 volumeSmoothTimeInPCMFrames;
|
||||
ma_mono_expansion_mode monoExpansionMode;
|
||||
ma_fader fader;
|
||||
ma_linear_resampler resampler; /* For pitch shift. */
|
||||
ma_resampler resampler; /* For pitch shift. */
|
||||
ma_spatializer spatializer;
|
||||
ma_panner panner;
|
||||
ma_gainer volumeGainer; /* This will only be used if volumeSmoothTimeInPCMFrames is > 0. */
|
||||
@@ -7497,6 +7500,7 @@ typedef struct
|
||||
ma_uint64 loopPointEndInPCMFrames;
|
||||
ma_sound_end_proc endCallback; /* Fired when the sound reaches the end. Will be fired from the audio thread. Do not restart, uninitialize or otherwise change the state of the sound from here. Instead fire an event or set a variable to indicate to a different thread to change the start of the sound. Will not be fired in response to a scheduled stop with ma_sound_set_stop_time_*(). */
|
||||
void* pEndCallbackUserData;
|
||||
ma_resampler_config pitchResampling;
|
||||
#ifndef MA_NO_RESOURCE_MANAGER
|
||||
ma_resource_manager_pipeline_notifications initNotifications;
|
||||
#endif
|
||||
@@ -7515,6 +7519,9 @@ struct ma_sound
|
||||
MA_ATOMIC(4, ma_bool32) atEnd;
|
||||
ma_sound_end_proc endCallback;
|
||||
void* pEndCallbackUserData;
|
||||
float* pProcessingCache; /* Will be null if pDataSource is null. */
|
||||
ma_uint32 processingCacheFramesRemaining;
|
||||
ma_uint32 processingCacheCap;
|
||||
ma_bool8 ownsDataSource;
|
||||
|
||||
/*
|
||||
@@ -7573,6 +7580,8 @@ typedef struct
|
||||
ma_vfs* pResourceManagerVFS; /* A pointer to a pre-allocated VFS object to use with the resource manager. This is ignored if pResourceManager is not NULL. */
|
||||
ma_engine_process_proc onProcess; /* Fired at the end of each call to ma_engine_read_pcm_frames(). For engine's that manage their own internal device (the default configuration), this will be fired from the audio thread, and you do not need to call ma_engine_read_pcm_frames() manually in order to trigger this. */
|
||||
void* pProcessUserData; /* User data that's passed into onProcess. */
|
||||
ma_resampler_config resourceManagerResampling; /* The resampling config to use with the resource manager. */
|
||||
ma_resampler_config pitchResampling; /* The resampling config for the pitch and Doppler effects. You will typically want this to be a fast resampler. For high quality stuff, it's recommended that you pre-resample. */
|
||||
} ma_engine_config;
|
||||
|
||||
MA_API ma_engine_config ma_engine_config_init(void);
|
||||
@@ -7602,6 +7611,7 @@ struct ma_engine
|
||||
ma_mono_expansion_mode monoExpansionMode;
|
||||
ma_engine_process_proc onProcess;
|
||||
void* pProcessUserData;
|
||||
ma_resampler_config pitchResamplingConfig;
|
||||
};
|
||||
|
||||
MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEngine);
|
||||
@@ -7662,8 +7672,12 @@ MA_API ma_engine* ma_sound_get_engine(const ma_sound* pSound);
|
||||
MA_API ma_data_source* ma_sound_get_data_source(const ma_sound* pSound);
|
||||
MA_API ma_result ma_sound_start(ma_sound* pSound);
|
||||
MA_API ma_result ma_sound_stop(ma_sound* pSound);
|
||||
MA_API ma_result ma_sound_stop_with_fade_in_pcm_frames(ma_sound* pSound, ma_uint64 fadeLengthInFrames); /* Will overwrite any scheduled stop and fade. */
|
||||
MA_API ma_result ma_sound_stop_with_fade_in_milliseconds(ma_sound* pSound, ma_uint64 fadeLengthInFrames); /* Will overwrite any scheduled stop and fade. */
|
||||
MA_API ma_result ma_sound_stop_with_fade_in_pcm_frames(ma_sound* pSound, ma_uint64 fadeLengthInFrames); /* Will overwrite any scheduled stop and fade. If you want to restart the sound, first reset it with `ma_sound_reset_stop_time_and_fade()`. There are plans to make this less awkward in the future. */
|
||||
MA_API ma_result ma_sound_stop_with_fade_in_milliseconds(ma_sound* pSound, ma_uint64 fadeLengthInFrames); /* Will overwrite any scheduled stop and fade. If you want to restart the sound, first reset it with `ma_sound_reset_stop_time_and_fade()`. There are plans to make this less awkward in the future. */
|
||||
MA_API void ma_sound_reset_start_time(ma_sound* pSound);
|
||||
MA_API void ma_sound_reset_stop_time(ma_sound* pSound);
|
||||
MA_API void ma_sound_reset_fade(ma_sound* pSound);
|
||||
MA_API void ma_sound_reset_stop_time_and_fade(ma_sound* pSound); /* Resets fades and scheduled stop time. Does not seek back to the start. */
|
||||
MA_API void ma_sound_set_volume(ma_sound* pSound, float volume);
|
||||
MA_API float ma_sound_get_volume(const ma_sound* pSound);
|
||||
MA_API void ma_sound_set_pan(ma_sound* pSound, float pan);
|
||||
@@ -7825,7 +7839,7 @@ For more information, please refer to <http://unlicense.org/>
|
||||
===============================================================================
|
||||
ALTERNATIVE 2 - MIT No Attribution
|
||||
===============================================================================
|
||||
Copyright 2025 David Reid
|
||||
Copyright 2026 David Reid
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
|
||||
+529
-314
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -33,7 +33,7 @@ c89str load_file(const char* pFilePath)
|
||||
|
||||
resultFS = fs_file_open_and_read(NULL, pFilePath, FS_FORMAT_TEXT, (void**)&pFileData, &fileSize);
|
||||
if (resultFS != FS_SUCCESS) {
|
||||
printf("Failed to open %s: %s.\n", pFilePath, fs_result_to_string(resultFS));
|
||||
printf("Failed to open %s: %s.\n", pFilePath, fs_result_description(resultFS));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ int save_file(const char* pFilePath, c89str src)
|
||||
|
||||
resultFS = fs_file_open_and_write(NULL, pFilePath, src, c89str_len(src));
|
||||
if (resultFS != FS_SUCCESS) {
|
||||
printf("Failed to save %s: %s.\n", pFilePath, fs_result_to_string(resultFS));
|
||||
printf("Failed to save %s: %s.\n", pFilePath, fs_result_description(resultFS));
|
||||
return (int)resultFS;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
</div>
|
||||
<table style="margin:0 auto; padding:1em 0px; text-align:center;">
|
||||
<tr>
|
||||
<td style="vertical-align:center;"><a style="padding:0;" href="https://www.reddit.com/r/miniaudio"><img src="{{ relative-path "img/reddit_white.svg" }}" style="margin:0; padding:0; height:40px; width:40px;"></a></td>
|
||||
<td style="vertical-align:center;"><a style="padding:0;" href="https://discord.gg/9vpqbjU"><img src="{{ relative-path "img/Discord-Logo-White.svg" }}" style="padding:0; height:32px; width:32px;"></a></td>
|
||||
<td rel="me" style="vertical-align:center;"><a style="padding:0;" href="https://fosstodon.org/@mackron"><img src="{{ relative-path "img/mastodon_white.svg" }}" style="padding:0; height:24px; width:32px;"></a></td>
|
||||
<td rel="me" style="vertical-align:center;"><a style="padding:0;" href="https://x.com/mackron"><img src="{{ relative-path "img/x_logo.svg" }}" style="padding:0; height:24px; width:24px;"></a></td>
|
||||
<td style="vertical-align:center;"><a style="padding:0;" href="https://github.com/mackron/miniaudio"><img src="{{ relative-path "img/github_white.png" }}" style="padding:0; height:24px; width:24px;"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -29,14 +29,11 @@
|
||||
</table>
|
||||
</td>
|
||||
|
||||
<td style="padding:0.1em; width:25%; text-align:right; vertical-align:center;">
|
||||
<a href="https://www.reddit.com/r/miniaudio"><img src="{{ relative-path "img/reddit_white.svg" }}" style="margin:0; padding:0; height:40px; width:40px;"></a>
|
||||
</td>
|
||||
<td style="padding:0.1em; width:25%; text-align:right; vertical-align:center;">
|
||||
<a href="https://discord.gg/9vpqbjU"><img src="{{ relative-path "img/Discord-Logo-White.svg" }}" style="margin:0; padding:0; height:32px; width:32px;"></a>
|
||||
</td>
|
||||
<td style="padding:0.1em; width:25%; text-align:right; vertical-align:center;">
|
||||
<a rel="me" href="https://fosstodon.org/@mackron"><img src="{{ relative-path "img/mastodon_white.svg" }}" style="margin:0; padding:0; height:24px; width:32px;"></a>
|
||||
<a rel="me" href="https://x.com/mackron"><img src="{{ relative-path "img/x_logo.svg" }}" style="margin:0; padding:0; height:24px; width:24px;"></a>
|
||||
</td>
|
||||
<td style="padding:0.1em; padding-right:1em; width:25%; text-align:right; vertical-align:center;">
|
||||
<a href="https://github.com/mackron/miniaudio"><img src="{{ relative-path "img/github_white.png" }}" style="margin:0; padding:0; height:24px; width:24px;"></a>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<svg width="74" height="79" viewBox="0 0 74 79" fill="white" xmlns="http://www.w3.org/2000/svg" class="w-5 h-5"><path d="M73.7014 17.9592C72.5616 9.62034 65.1774 3.04876 56.424 1.77536C54.9472 1.56019 49.3517 0.7771 36.3901 0.7771H36.2933C23.3281 0.7771 20.5465 1.56019 19.0697 1.77536C10.56 3.01348 2.78877 8.91838 0.903306 17.356C-0.00357857 21.5113 -0.100361 26.1181 0.068112 30.3439C0.308275 36.404 0.354874 42.4535 0.91406 48.489C1.30064 52.498 1.97502 56.4751 2.93215 60.3905C4.72441 67.6217 11.9795 73.6395 19.0876 76.0945C26.6979 78.6548 34.8821 79.0799 42.724 77.3221C43.5866 77.1245 44.4398 76.8953 45.2833 76.6342C47.1867 76.0381 49.4199 75.3714 51.0616 74.2003C51.0841 74.1839 51.1026 74.1627 51.1156 74.1382C51.1286 74.1138 51.1359 74.0868 51.1368 74.0592V68.2108C51.1364 68.185 51.1302 68.1596 51.1185 68.1365C51.1069 68.1134 51.0902 68.0932 51.0695 68.0773C51.0489 68.0614 51.0249 68.0503 50.9994 68.0447C50.9738 68.0391 50.9473 68.0392 50.9218 68.045C45.8976 69.226 40.7491 69.818 35.5836 69.8087C26.694 69.8087 24.3031 65.6569 23.6184 63.9285C23.0681 62.4347 22.7186 60.8764 22.5789 59.2934C22.5775 59.2669 22.5825 59.2403 22.5934 59.216C22.6043 59.1916 22.621 59.1702 22.6419 59.1533C22.6629 59.1365 22.6876 59.1248 22.714 59.1191C22.7404 59.1134 22.7678 59.1139 22.794 59.1206C27.7345 60.2936 32.799 60.8856 37.8813 60.8843C39.1036 60.8843 40.3223 60.8843 41.5447 60.8526C46.6562 60.7115 52.0437 60.454 57.0728 59.4874C57.1983 59.4628 57.3237 59.4416 57.4313 59.4098C65.3638 57.9107 72.9128 53.2051 73.6799 41.2895C73.7086 40.8204 73.7803 36.3758 73.7803 35.889C73.7839 34.2347 74.3216 24.1533 73.7014 17.9592ZM61.4925 47.6918H53.1514V27.5855C53.1514 23.3526 51.3591 21.1938 47.7136 21.1938C43.7061 21.1938 41.6988 23.7476 41.6988 28.7919V39.7974H33.4078V28.7919C33.4078 23.7476 31.3969 21.1938 27.3894 21.1938C23.7654 21.1938 21.9552 23.3526 21.9516 27.5855V47.6918H13.6176V26.9752C13.6176 22.7423 14.7157 19.3795 16.9118 16.8868C19.1772 14.4 22.1488 13.1231 25.8373 13.1231C30.1064 13.1231 33.3325 14.7386 35.4832 17.9662L37.5587 21.3949L39.6377 17.9662C41.7884 14.7386 45.0145 13.1231 49.2765 13.1231C52.9614 13.1231 55.9329 14.4 58.2055 16.8868C60.4017 19.3772 61.4997 22.74 61.4997 26.9752L61.4925 47.6918Z" fill="inherit"></path></svg>
|
||||
|
Before Width: | Height: | Size: 2.2 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><g><circle fill="none" cx="10" cy="10" r="10"/><path fill="#FFF" d="M16.67,10A1.46,1.46,0,0,0,14.2,9a7.12,7.12,0,0,0-3.85-1.23L11,4.65,13.14,5.1a1,1,0,1,0,.13-0.61L10.82,4a0.31,0.31,0,0,0-.37.24L9.71,7.71a7.14,7.14,0,0,0-3.9,1.23A1.46,1.46,0,1,0,4.2,11.33a2.87,2.87,0,0,0,0,.44c0,2.24,2.61,4.06,5.83,4.06s5.83-1.82,5.83-4.06a2.87,2.87,0,0,0,0-.44A1.46,1.46,0,0,0,16.67,10Zm-10,1a1,1,0,1,1,1,1A1,1,0,0,1,6.67,11Zm5.81,2.75a3.84,3.84,0,0,1-2.47.77,3.84,3.84,0,0,1-2.47-.77,0.27,0.27,0,0,1,.38-0.38A3.27,3.27,0,0,0,10,14a3.28,3.28,0,0,0,2.09-.61A0.27,0.27,0,1,1,12.48,13.79Zm-0.18-1.71a1,1,0,1,1,1-1A1,1,0,0,1,12.29,12.08Z"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 692 B |
Binary file not shown.
|
Before Width: | Height: | Size: 2.2 KiB |
@@ -0,0 +1,3 @@
|
||||
<svg width="1200" height="1227" viewBox="0 0 1200 1227" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M714.163 519.284L1160.89 0H1055.03L667.137 450.887L357.328 0H0L468.492 681.821L0 1226.37H105.866L515.491 750.218L842.672 1226.37H1200L714.137 519.284H714.163ZM569.165 687.828L521.697 619.934L144.011 79.6944H306.615L611.412 515.685L658.88 583.579L1055.08 1150.3H892.476L569.165 687.854V687.828Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 430 B |
Reference in New Issue
Block a user