diff --git a/src/external/cgltf.h b/src/external/cgltf.h index 85d5c9850..7f3f77f7f 100644 --- a/src/external/cgltf.h +++ b/src/external/cgltf.h @@ -1,7 +1,7 @@ /** * cgltf - a single-file glTF 2.0 parser written in C99. * - * Version: 1.0 + * Version: 1.2 * * Website: https://github.com/jkuhlmann/cgltf * @@ -35,8 +35,15 @@ * variable. * * `cgltf_result cgltf_load_buffers(const cgltf_options*, cgltf_data*, - * const char*)` can be optionally called to open and read buffer - * files using the `FILE*` APIs. + * const char* gltf_path)` can be optionally called to open and read buffer + * files using the `FILE*` APIs. The `gltf_path` argument is the path to + * the original glTF file, which allows the parser to resolve the path to + * buffer files. + * + * `cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, + * cgltf_size size, const char* base64, void** out_data)` decodes + * base64-encoded data content. Used internally by `cgltf_load_buffers()` + * and may be useful if you're not dealing with normal files. * * `cgltf_result cgltf_parse_file(const cgltf_options* options, const * char* path, cgltf_data** out_data)` can be used to open the given @@ -44,6 +51,29 @@ * * `cgltf_result cgltf_validate(cgltf_data*)` can be used to do additional * checks to make sure the parsed glTF data is valid. + * + * `cgltf_node_transform_local` converts the translation / rotation / scale properties of a node + * into a mat4. + * + * `cgltf_node_transform_world` calls `cgltf_node_transform_local` on every ancestor in order + * to compute the root-to-node transformation. + * + * `cgltf_accessor_read_float` reads a certain element from an accessor and converts it to + * floating point, assuming that `cgltf_load_buffers` has already been called. The passed-in element + * size is the number of floats in the output buffer, which should be in the range [1, 16]. Returns + * false if the passed-in element_size is too small, or if the accessor is sparse. + * + * `cgltf_accessor_read_index` is similar to its floating-point counterpart, but it returns size_t + * and only works with single-component data types. + * + * `cgltf_result cgltf_copy_extras_json(const cgltf_data*, const cgltf_extras*, + * char* dest, cgltf_size* dest_size)` allows to retrieve the "extras" data that + * can be attached to many glTF objects (which can be arbitrary JSON data). The + * `cgltf_extras` struct stores the offsets of the start and end of the extras JSON data + * as it appears in the complete glTF JSON data. This function copies the extras data + * into the provided buffer. If `dest` is NULL, the length of the data is written into + * `dest_size`. You can then parse this data using your own JSON parser + * or, if you've included the cgltf implementation using the integrated JSMN JSON parser. */ #ifndef CGLTF_H_INCLUDED__ #define CGLTF_H_INCLUDED__ @@ -175,11 +205,17 @@ typedef enum cgltf_light_type { cgltf_light_type_spot, } cgltf_light_type; +typedef struct cgltf_extras { + cgltf_size start_offset; + cgltf_size end_offset; +} cgltf_extras; + typedef struct cgltf_buffer { cgltf_size size; char* uri; void* data; /* loaded by cgltf_load_buffers */ + cgltf_extras extras; } cgltf_buffer; typedef struct cgltf_buffer_view @@ -189,6 +225,7 @@ typedef struct cgltf_buffer_view cgltf_size size; cgltf_size stride; /* 0 == automatically determined by accessor */ cgltf_buffer_view_type type; + cgltf_extras extras; } cgltf_buffer_view; typedef struct cgltf_accessor_sparse @@ -199,6 +236,9 @@ typedef struct cgltf_accessor_sparse cgltf_component_type indices_component_type; cgltf_buffer_view* values_buffer_view; cgltf_size values_byte_offset; + cgltf_extras extras; + cgltf_extras indices_extras; + cgltf_extras values_extras; } cgltf_accessor_sparse; typedef struct cgltf_accessor @@ -216,6 +256,7 @@ typedef struct cgltf_accessor cgltf_float max[16]; cgltf_bool is_sparse; cgltf_accessor_sparse sparse; + cgltf_extras extras; } cgltf_accessor; typedef struct cgltf_attribute @@ -232,6 +273,7 @@ typedef struct cgltf_image char* uri; cgltf_buffer_view* buffer_view; char* mime_type; + cgltf_extras extras; } cgltf_image; typedef struct cgltf_sampler @@ -240,6 +282,7 @@ typedef struct cgltf_sampler cgltf_int min_filter; cgltf_int wrap_s; cgltf_int wrap_t; + cgltf_extras extras; } cgltf_sampler; typedef struct cgltf_texture @@ -247,6 +290,7 @@ typedef struct cgltf_texture char* name; cgltf_image* image; cgltf_sampler* sampler; + cgltf_extras extras; } cgltf_texture; typedef struct cgltf_texture_transform @@ -264,6 +308,7 @@ typedef struct cgltf_texture_view cgltf_float scale; /* equivalent to strength for occlusion_texture */ cgltf_bool has_transform; cgltf_texture_transform transform; + cgltf_extras extras; } cgltf_texture_view; typedef struct cgltf_pbr_metallic_roughness @@ -274,6 +319,8 @@ typedef struct cgltf_pbr_metallic_roughness cgltf_float base_color_factor[4]; cgltf_float metallic_factor; cgltf_float roughness_factor; + + cgltf_extras extras; } cgltf_pbr_metallic_roughness; typedef struct cgltf_pbr_specular_glossiness @@ -301,6 +348,7 @@ typedef struct cgltf_material cgltf_float alpha_cutoff; cgltf_bool double_sided; cgltf_bool unlit; + cgltf_extras extras; } cgltf_material; typedef struct cgltf_morph_target { @@ -316,6 +364,7 @@ typedef struct cgltf_primitive { cgltf_size attributes_count; cgltf_morph_target* targets; cgltf_size targets_count; + cgltf_extras extras; } cgltf_primitive; typedef struct cgltf_mesh { @@ -324,6 +373,7 @@ typedef struct cgltf_mesh { cgltf_size primitives_count; cgltf_float* weights; cgltf_size weights_count; + cgltf_extras extras; } cgltf_mesh; typedef struct cgltf_node cgltf_node; @@ -334,6 +384,7 @@ typedef struct cgltf_skin { cgltf_size joints_count; cgltf_node* skeleton; cgltf_accessor* inverse_bind_matrices; + cgltf_extras extras; } cgltf_skin; typedef struct cgltf_camera_perspective { @@ -341,6 +392,7 @@ typedef struct cgltf_camera_perspective { cgltf_float yfov; cgltf_float zfar; cgltf_float znear; + cgltf_extras extras; } cgltf_camera_perspective; typedef struct cgltf_camera_orthographic { @@ -348,6 +400,7 @@ typedef struct cgltf_camera_orthographic { cgltf_float ymag; cgltf_float zfar; cgltf_float znear; + cgltf_extras extras; } cgltf_camera_orthographic; typedef struct cgltf_camera { @@ -357,6 +410,7 @@ typedef struct cgltf_camera { cgltf_camera_perspective perspective; cgltf_camera_orthographic orthographic; }; + cgltf_extras extras; } cgltf_camera; typedef struct cgltf_light { @@ -388,24 +442,28 @@ struct cgltf_node { cgltf_float rotation[4]; cgltf_float scale[3]; cgltf_float matrix[16]; + cgltf_extras extras; }; typedef struct cgltf_scene { char* name; cgltf_node** nodes; cgltf_size nodes_count; + cgltf_extras extras; } cgltf_scene; typedef struct cgltf_animation_sampler { cgltf_accessor* input; cgltf_accessor* output; cgltf_interpolation_type interpolation; + cgltf_extras extras; } cgltf_animation_sampler; typedef struct cgltf_animation_channel { cgltf_animation_sampler* sampler; cgltf_node* target_node; cgltf_animation_path_type target_path; + cgltf_extras extras; } cgltf_animation_channel; typedef struct cgltf_animation { @@ -414,6 +472,7 @@ typedef struct cgltf_animation { cgltf_size samplers_count; cgltf_animation_channel* channels; cgltf_size channels_count; + cgltf_extras extras; } cgltf_animation; typedef struct cgltf_asset { @@ -421,6 +480,7 @@ typedef struct cgltf_asset { char* generator; char* version; char* min_version; + cgltf_extras extras; } cgltf_asset; typedef struct cgltf_data @@ -474,6 +534,17 @@ typedef struct cgltf_data cgltf_animation* animations; cgltf_size animations_count; + cgltf_extras extras; + + char** extensions_used; + cgltf_size extensions_used_count; + + char** extensions_required; + cgltf_size extensions_required_count; + + const char* json; + cgltf_size json_size; + const void* bin; cgltf_size bin_size; @@ -495,7 +566,10 @@ cgltf_result cgltf_parse_file( cgltf_result cgltf_load_buffers( const cgltf_options* options, cgltf_data* data, - const char* base_path); + const char* gltf_path); + + +cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, cgltf_size size, const char* base64, void** out_data); cgltf_result cgltf_validate( cgltf_data* data); @@ -505,6 +579,11 @@ void cgltf_free(cgltf_data* data); void cgltf_node_transform_local(const cgltf_node* node, cgltf_float* out_matrix); void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix); +cgltf_bool cgltf_accessor_read_float(const cgltf_accessor* accessor, cgltf_size index, cgltf_float* out, cgltf_size element_size); +cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size index); + +cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* extras, char* dest, cgltf_size* dest_size); + #ifdef __cplusplus } #endif @@ -528,7 +607,14 @@ void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix) #include /* For uint8_t, uint32_t */ #include /* For strncpy */ #include /* For malloc, free */ -#include /* For fopen */ +#include /* For fopen */ +#include /* For UINT_MAX etc */ + +/* JSMN_PARENT_LINKS is necessary to make parsing large structures linear in input size */ +#define JSMN_PARENT_LINKS + +/* JSMN_STRICT is necessary to reject invalid JSON documents */ +#define JSMN_STRICT /* * -- jsmn.h start -- @@ -580,11 +666,13 @@ static const uint32_t GlbMagicBinChunk = 0x004E4942; static void* cgltf_default_alloc(void* user, cgltf_size size) { + (void)user; return malloc(size); } static void cgltf_default_free(void* user, void* ptr) { + (void)user; free(ptr); } @@ -810,22 +898,22 @@ static void cgltf_combine_paths(char* path, const char* base, const char* uri) } else { - strcpy(path, base); + strcpy(path, uri); } } -static cgltf_result cgltf_load_buffer_file(const cgltf_options* options, cgltf_size size, const char* uri, const char* base_path, void** out_data) +static cgltf_result cgltf_load_buffer_file(const cgltf_options* options, cgltf_size size, const char* uri, const char* gltf_path, void** out_data) { void* (*memory_alloc)(void*, cgltf_size) = options->memory_alloc ? options->memory_alloc : &cgltf_default_alloc; void (*memory_free)(void*, void*) = options->memory_free ? options->memory_free : &cgltf_default_free; - char* path = (char*)memory_alloc(options->memory_user_data, strlen(uri) + strlen(base_path) + 1); + char* path = (char*)memory_alloc(options->memory_user_data, strlen(uri) + strlen(gltf_path) + 1); if (!path) { return cgltf_result_out_of_memory; } - cgltf_combine_paths(path, base_path, uri); + cgltf_combine_paths(path, gltf_path, uri); FILE* file = fopen(path, "rb"); @@ -858,7 +946,7 @@ static cgltf_result cgltf_load_buffer_file(const cgltf_options* options, cgltf_s return cgltf_result_success; } -static cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, cgltf_size size, const char* base64, void** out_data) +cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, cgltf_size size, const char* base64, void** out_data) { void* (*memory_alloc)(void*, cgltf_size) = options->memory_alloc ? options->memory_alloc : &cgltf_default_alloc; void (*memory_free)(void*, void*) = options->memory_free ? options->memory_free : &cgltf_default_free; @@ -905,7 +993,7 @@ static cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, cgltf return cgltf_result_success; } -cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data, const char* base_path) +cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data, const char* gltf_path) { if (options == NULL) { @@ -954,9 +1042,9 @@ cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data, return cgltf_result_unknown_format; } } - else if (strstr(uri, "://") == NULL) + else if (strstr(uri, "://") == NULL && gltf_path) { - cgltf_result res = cgltf_load_buffer_file(options, data->buffers[i].size, uri, base_path, &data->buffers[i].data); + cgltf_result res = cgltf_load_buffer_file(options, data->buffers[i].size, uri, gltf_path, &data->buffers[i].data); if (res != cgltf_result_success) { @@ -1150,6 +1238,34 @@ cgltf_result cgltf_validate(cgltf_data* data) return cgltf_result_success; } +cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* extras, char* dest, cgltf_size* dest_size) +{ + cgltf_size json_size = extras->end_offset - extras->start_offset; + + if (!dest) + { + if (dest_size) + { + *dest_size = json_size + 1; + return cgltf_result_success; + } + return cgltf_result_invalid_options; + } + + if (*dest_size + 1 < json_size) + { + strncpy(dest, data->json + extras->start_offset, *dest_size - 1); + dest[*dest_size - 1] = 0; + } + else + { + strncpy(dest, data->json + extras->start_offset, json_size); + dest[json_size] = 0; + } + + return cgltf_result_success; +} + void cgltf_free(cgltf_data* data) { if (!data) @@ -1282,6 +1398,20 @@ void cgltf_free(cgltf_data* data) data->memory_free(data->memory_user_data, data->animations); + for (cgltf_size i = 0; i < data->extensions_used_count; ++i) + { + data->memory_free(data->memory_user_data, data->extensions_used[i]); + } + + data->memory_free(data->memory_user_data, data->extensions_used); + + for (cgltf_size i = 0; i < data->extensions_required_count; ++i) + { + data->memory_free(data->memory_user_data, data->extensions_required[i]); + } + + data->memory_free(data->memory_user_data, data->extensions_required); + data->memory_free(data->memory_user_data, data->file_data); data->memory_free(data->memory_user_data, data); @@ -1367,6 +1497,142 @@ void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix) } } +static cgltf_size cgltf_component_read_index(const void* in, cgltf_component_type component_type) +{ + switch (component_type) + { + case cgltf_component_type_r_16: + return *((const int16_t*) in); + case cgltf_component_type_r_16u: + return *((const uint16_t*) in); + case cgltf_component_type_r_32u: + return *((const uint32_t*) in); + case cgltf_component_type_r_32f: + return (cgltf_size)*((const float*) in); + case cgltf_component_type_r_8: + return *((const int8_t*) in); + case cgltf_component_type_r_8u: + case cgltf_component_type_invalid: + default: + return *((const uint8_t*) in); + } +} + +static cgltf_float cgltf_component_read_float(const void* in, cgltf_component_type component_type, cgltf_bool normalized) +{ + if (component_type == cgltf_component_type_r_32f) + { + return *((const float*) in); + } + + if (normalized) + { + switch (component_type) + { + case cgltf_component_type_r_32u: + return *((const uint32_t*) in) / (float) UINT_MAX; + case cgltf_component_type_r_16: + return *((const int16_t*) in) / (float) SHRT_MAX; + case cgltf_component_type_r_16u: + return *((const uint16_t*) in) / (float) USHRT_MAX; + case cgltf_component_type_r_8: + return *((const int8_t*) in) / (float) SCHAR_MAX; + case cgltf_component_type_r_8u: + case cgltf_component_type_invalid: + default: + return *((const uint8_t*) in) / (float) CHAR_MAX; + } + } + + return (cgltf_float)cgltf_component_read_index(in, component_type); +} + +static cgltf_size cgltf_num_components(cgltf_type type); +static cgltf_size cgltf_component_size(cgltf_component_type component_type); + +static 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) +{ + cgltf_size num_components = cgltf_num_components(type); + + if (element_size < num_components) { + return 0; + } + + // There are three special cases for component extraction, see #data-alignment in the 2.0 spec. + + cgltf_size component_size = cgltf_component_size(component_type); + + if (type == cgltf_type_mat2 && component_size == 1) + { + out[0] = cgltf_component_read_float(element, component_type, normalized); + out[1] = cgltf_component_read_float(element + 1, component_type, normalized); + out[2] = cgltf_component_read_float(element + 4, component_type, normalized); + out[3] = cgltf_component_read_float(element + 5, component_type, normalized); + return 1; + } + + if (type == cgltf_type_mat3 && component_size == 1) + { + out[0] = cgltf_component_read_float(element, component_type, normalized); + out[1] = cgltf_component_read_float(element + 1, component_type, normalized); + out[2] = cgltf_component_read_float(element + 2, component_type, normalized); + out[3] = cgltf_component_read_float(element + 4, component_type, normalized); + out[4] = cgltf_component_read_float(element + 5, component_type, normalized); + out[5] = cgltf_component_read_float(element + 6, component_type, normalized); + out[6] = cgltf_component_read_float(element + 8, component_type, normalized); + out[7] = cgltf_component_read_float(element + 9, component_type, normalized); + out[8] = cgltf_component_read_float(element + 10, component_type, normalized); + return 1; + } + + if (type == cgltf_type_mat3 && component_size == 2) + { + out[0] = cgltf_component_read_float(element, component_type, normalized); + out[1] = cgltf_component_read_float(element + 2, component_type, normalized); + out[2] = cgltf_component_read_float(element + 4, component_type, normalized); + out[3] = cgltf_component_read_float(element + 8, component_type, normalized); + out[4] = cgltf_component_read_float(element + 10, component_type, normalized); + out[5] = cgltf_component_read_float(element + 12, component_type, normalized); + out[6] = cgltf_component_read_float(element + 16, component_type, normalized); + out[7] = cgltf_component_read_float(element + 18, component_type, normalized); + out[8] = cgltf_component_read_float(element + 20, component_type, normalized); + return 1; + } + + for (cgltf_size i = 0; i < num_components; ++i) + { + out[i] = cgltf_component_read_float(element + component_size * i, component_type, normalized); + } + return 1; +} + + +cgltf_bool cgltf_accessor_read_float(const cgltf_accessor* accessor, cgltf_size index, cgltf_float* out, cgltf_size element_size) +{ + if (accessor->is_sparse || accessor->buffer_view == NULL) + { + return 0; + } + + cgltf_size offset = accessor->offset + accessor->buffer_view->offset; + const uint8_t* element = (const uint8_t*) accessor->buffer_view->buffer->data; + element += offset + accessor->stride * index; + return cgltf_element_read_float(element, accessor->type, accessor->component_type, accessor->normalized, out, element_size); +} + +cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size index) +{ + if (accessor->buffer_view) + { + cgltf_size offset = accessor->offset + accessor->buffer_view->offset; + const uint8_t* element = (const uint8_t*) accessor->buffer_view->buffer->data; + element += offset + accessor->stride * index; + return cgltf_component_read_index(element, accessor->component_type); + } + + return 0; +} + #define CGLTF_ERROR_JSON -1 #define CGLTF_ERROR_NOMEM -2 @@ -1413,39 +1679,31 @@ static cgltf_bool cgltf_json_to_bool(jsmntok_t const* tok, const uint8_t* json_c static int cgltf_skip_json(jsmntok_t const* tokens, int i) { - if (tokens[i].type == JSMN_ARRAY) - { - int size = tokens[i].size; - ++i; - for (int j = 0; j < size; ++j) - { - i = cgltf_skip_json(tokens, i); - if (i < 0) - { - return i; - } - } - } - else if (tokens[i].type == JSMN_OBJECT) + int end = i + 1; + + while (i < end) { - int size = tokens[i].size; - ++i; - for (int j = 0; j < size; ++j) + switch (tokens[i].type) { - CGLTF_CHECK_KEY(tokens[i]); - ++i; - i = cgltf_skip_json(tokens, i); - if (i < 0) - { - return i; - } + case JSMN_OBJECT: + end += tokens[i].size * 2; + break; + + case JSMN_ARRAY: + end += tokens[i].size; + break; + + case JSMN_PRIMITIVE: + case JSMN_STRING: + break; + + default: + return -1; } + + i++; } - else if (tokens[i].type == JSMN_PRIMITIVE - || tokens[i].type == JSMN_STRING) - { - return i + 1; - } + return i; } @@ -1495,6 +1753,7 @@ static int cgltf_parse_json_string(cgltf_options* options, jsmntok_t const* toke static 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) { + (void)json_chunk; CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_ARRAY); if (*out_array) { @@ -1511,6 +1770,26 @@ static int cgltf_parse_json_array(cgltf_options* options, jsmntok_t const* token return i + 1; } +static 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) +{ + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_ARRAY); + i = cgltf_parse_json_array(options, tokens, i, json_chunk, sizeof(char*), (void**)out_array, out_size); + if (i < 0) + { + return i; + } + + for (cgltf_size j = 0; j < *out_size; ++j) + { + i = cgltf_parse_json_string(options, tokens, i, json_chunk, j + (*out_array)); + if (i < 0) + { + return i; + } + } + return i; +} + static void cgltf_parse_attribute_type(const char* name, cgltf_attribute_type* out_type, int* out_index) { const char* us = strchr(name, '_'); @@ -1592,6 +1871,15 @@ static int cgltf_parse_json_attribute_list(cgltf_options* options, jsmntok_t con return i; } +static int cgltf_parse_json_extras(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_extras* out_extras) +{ + (void)json_chunk; + out_extras->start_offset = tokens[i].start; + out_extras->end_offset = tokens[i].end; + i = cgltf_skip_json(tokens, i); + return i; +} + static int cgltf_parse_json_primitive(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_primitive* out_prim) { CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); @@ -1637,15 +1925,19 @@ static int cgltf_parse_json_primitive(cgltf_options* options, jsmntok_t const* t return i; } - for (cgltf_size j = 0; j < out_prim->targets_count; ++j) + for (cgltf_size k = 0; k < out_prim->targets_count; ++k) { - i = cgltf_parse_json_attribute_list(options, tokens, i, json_chunk, &out_prim->targets[j].attributes, &out_prim->targets[j].attributes_count); + i = cgltf_parse_json_attribute_list(options, tokens, i, json_chunk, &out_prim->targets[k].attributes, &out_prim->targets[k].attributes_count); if (i < 0) { return i; } } } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_prim->extras); + } else { i = cgltf_skip_json(tokens, i+1); @@ -1702,6 +1994,10 @@ static int cgltf_parse_json_mesh(cgltf_options* options, jsmntok_t const* tokens i = cgltf_parse_json_float_array(tokens, i - 1, json_chunk, out_mesh->weights, (int)out_mesh->weights_count); } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_mesh->extras); + } else { i = cgltf_skip_json(tokens, i+1); @@ -1805,6 +2101,10 @@ static int cgltf_parse_json_accessor_sparse(jsmntok_t const* tokens, int i, cons out_sparse->indices_component_type = cgltf_json_to_component_type(tokens + i, json_chunk); ++i; } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_sparse->indices_extras); + } else { i = cgltf_skip_json(tokens, i+1); @@ -1840,6 +2140,10 @@ static int cgltf_parse_json_accessor_sparse(jsmntok_t const* tokens, int i, cons out_sparse->values_byte_offset = cgltf_json_to_int(tokens + i, json_chunk); ++i; } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_sparse->values_extras); + } else { i = cgltf_skip_json(tokens, i+1); @@ -1851,6 +2155,10 @@ static int cgltf_parse_json_accessor_sparse(jsmntok_t const* tokens, int i, cons } } } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_sparse->extras); + } else { i = cgltf_skip_json(tokens, i+1); @@ -1962,6 +2270,10 @@ static int cgltf_parse_json_accessor(jsmntok_t const* tokens, int i, const uint8 out_accessor->is_sparse = 1; i = cgltf_parse_json_accessor_sparse(tokens, i + 1, json_chunk, &out_accessor->sparse); } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_accessor->extras); + } else { i = cgltf_skip_json(tokens, i+1); @@ -2059,6 +2371,10 @@ static int cgltf_parse_json_texture_view(jsmntok_t const* tokens, int i, const u out_texture_view->scale = cgltf_json_to_float(tokens + i, json_chunk); ++i; } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_texture_view->extras); + } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { ++i; @@ -2070,6 +2386,8 @@ static int cgltf_parse_json_texture_view(jsmntok_t const* tokens, int i, const u for (int k = 0; k < extensions_size; ++k) { + CGLTF_CHECK_KEY(tokens[i]); + if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_texture_transform") == 0) { out_texture_view->has_transform = 1; @@ -2079,6 +2397,11 @@ static int cgltf_parse_json_texture_view(jsmntok_t const* tokens, int i, const u { i = cgltf_skip_json(tokens, i+1); } + + if (i < 0) + { + return i; + } } } else @@ -2134,6 +2457,10 @@ static int cgltf_parse_json_pbr_metallic_roughness(jsmntok_t const* tokens, int i = cgltf_parse_json_texture_view(tokens, i + 1, json_chunk, &out_pbr->metallic_roughness_texture); } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_pbr->extras); + } else { i = cgltf_skip_json(tokens, i+1); @@ -2161,18 +2488,10 @@ static int cgltf_parse_json_pbr_specular_glossiness(jsmntok_t const* tokens, int if (cgltf_json_strcmp(tokens+i, json_chunk, "diffuseFactor") == 0) { i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_pbr->diffuse_factor, 4); - if (i < 0) - { - return i; - } } else if (cgltf_json_strcmp(tokens+i, json_chunk, "specularFactor") == 0) { i = cgltf_parse_json_float_array(tokens, i + 1, json_chunk, out_pbr->specular_factor, 3); - if (i < 0) - { - return i; - } } else if (cgltf_json_strcmp(tokens+i, json_chunk, "glossinessFactor") == 0) { @@ -2183,18 +2502,10 @@ static int cgltf_parse_json_pbr_specular_glossiness(jsmntok_t const* tokens, int else if (cgltf_json_strcmp(tokens+i, json_chunk, "diffuseTexture") == 0) { i = cgltf_parse_json_texture_view(tokens, i + 1, json_chunk, &out_pbr->diffuse_texture); - if (i < 0) - { - return i; - } } else if (cgltf_json_strcmp(tokens+i, json_chunk, "specularGlossinessTexture") == 0) { i = cgltf_parse_json_texture_view(tokens, i + 1, json_chunk, &out_pbr->specular_glossiness_texture); - if (i < 0) - { - return i; - } } else { @@ -2205,7 +2516,6 @@ static int cgltf_parse_json_pbr_specular_glossiness(jsmntok_t const* tokens, int { return i; } - } return i; @@ -2240,6 +2550,10 @@ static int cgltf_parse_json_image(cgltf_options* options, jsmntok_t const* token { i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_image->name); } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_image->extras); + } else { i = cgltf_skip_json(tokens, i + 1); @@ -2256,6 +2570,7 @@ static int cgltf_parse_json_image(cgltf_options* options, jsmntok_t const* token static int cgltf_parse_json_sampler(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_sampler* out_sampler) { + (void)options; CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); out_sampler->wrap_s = 10497; @@ -2296,6 +2611,10 @@ static int cgltf_parse_json_sampler(cgltf_options* options, jsmntok_t const* tok = cgltf_json_to_int(tokens + i, json_chunk); ++i; } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_sampler->extras); + } else { i = cgltf_skip_json(tokens, i + 1); @@ -2338,6 +2657,10 @@ static int cgltf_parse_json_texture(cgltf_options* options, jsmntok_t const* tok out_texture->image = CGLTF_PTRINDEX(cgltf_image, cgltf_json_to_int(tokens + i, json_chunk)); ++i; } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_texture->extras); + } else { i = cgltf_skip_json(tokens, i + 1); @@ -2431,6 +2754,10 @@ static int cgltf_parse_json_material(cgltf_options* options, jsmntok_t const* to cgltf_json_to_bool(tokens + i, json_chunk); ++i; } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_material->extras); + } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { ++i; @@ -2631,6 +2958,10 @@ static int cgltf_parse_json_buffer_view(jsmntok_t const* tokens, int i, const ui out_buffer_view->type = (cgltf_buffer_view_type)type; ++i; } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_buffer_view->extras); + } else { i = cgltf_skip_json(tokens, i+1); @@ -2686,6 +3017,10 @@ static int cgltf_parse_json_buffer(cgltf_options* options, jsmntok_t const* toke { i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_buffer->uri); } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_buffer->extras); + } else { i = cgltf_skip_json(tokens, i+1); @@ -2762,6 +3097,10 @@ static int cgltf_parse_json_skin(cgltf_options* options, jsmntok_t const* tokens out_skin->inverse_bind_matrices = CGLTF_PTRINDEX(cgltf_accessor, cgltf_json_to_int(tokens + i, json_chunk)); ++i; } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_skin->extras); + } else { i = cgltf_skip_json(tokens, i+1); @@ -2862,6 +3201,10 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke out_camera->perspective.znear = cgltf_json_to_float(tokens + i, json_chunk); ++i; } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_camera->perspective.extras); + } else { i = cgltf_skip_json(tokens, i+1); @@ -2912,6 +3255,10 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke out_camera->orthographic.znear = cgltf_json_to_float(tokens + i, json_chunk); ++i; } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_camera->orthographic.extras); + } else { i = cgltf_skip_json(tokens, i+1); @@ -2923,6 +3270,10 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke } } } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_camera->extras); + } else { i = cgltf_skip_json(tokens, i+1); @@ -3162,6 +3513,10 @@ static int cgltf_parse_json_node(cgltf_options* options, jsmntok_t const* tokens i = cgltf_parse_json_float_array(tokens, i - 1, json_chunk, out_node->weights, (int)out_node->weights_count); } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_node->extras); + } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { ++i; @@ -3279,6 +3634,10 @@ static int cgltf_parse_json_scene(cgltf_options* options, jsmntok_t const* token ++i; } } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_scene->extras); + } else { i = cgltf_skip_json(tokens, i+1); @@ -3314,6 +3673,7 @@ static int cgltf_parse_json_scenes(cgltf_options* options, jsmntok_t const* toke static 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) { + (void)options; CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); int size = tokens[i].size; @@ -3352,6 +3712,10 @@ static int cgltf_parse_json_animation_sampler(cgltf_options* options, jsmntok_t } ++i; } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_sampler->extras); + } else { i = cgltf_skip_json(tokens, i+1); @@ -3368,6 +3732,7 @@ static int cgltf_parse_json_animation_sampler(cgltf_options* options, jsmntok_t static 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) { + (void)options; CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); int size = tokens[i].size; @@ -3423,6 +3788,10 @@ static int cgltf_parse_json_animation_channel(cgltf_options* options, jsmntok_t } ++i; } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_channel->extras); + } else { i = cgltf_skip_json(tokens, i+1); @@ -3497,6 +3866,10 @@ static int cgltf_parse_json_animation(cgltf_options* options, jsmntok_t const* t } } } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_animation->extras); + } else { i = cgltf_skip_json(tokens, i+1); @@ -3557,6 +3930,10 @@ static int cgltf_parse_json_asset(cgltf_options* options, jsmntok_t const* token { i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_asset->min_version); } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_asset->extras); + } else { i = cgltf_skip_json(tokens, i+1); @@ -3571,58 +3948,58 @@ static int cgltf_parse_json_asset(cgltf_options* options, jsmntok_t const* token return i; } -static cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type) -{ - cgltf_size size = 0; +static cgltf_size cgltf_num_components(cgltf_type type) { + switch (type) + { + case cgltf_type_vec2: + return 2; + case cgltf_type_vec3: + return 3; + case cgltf_type_vec4: + return 4; + case cgltf_type_mat2: + return 4; + case cgltf_type_mat3: + return 9; + case cgltf_type_mat4: + return 16; + case cgltf_type_invalid: + case cgltf_type_scalar: + default: + return 1; + } +} +static cgltf_size cgltf_component_size(cgltf_component_type component_type) { switch (component_type) { case cgltf_component_type_r_8: case cgltf_component_type_r_8u: - size = 1; - break; + return 1; case cgltf_component_type_r_16: case cgltf_component_type_r_16u: - size = 2; - break; + return 2; case cgltf_component_type_r_32u: case cgltf_component_type_r_32f: - size = 4; - break; + return 4; case cgltf_component_type_invalid: default: - size = 0; - break; + return 0; } +} - switch (type) +static cgltf_size cgltf_calc_size(cgltf_type type, cgltf_component_type component_type) +{ + cgltf_size component_size = cgltf_component_size(component_type); + if (type == cgltf_type_mat2 && component_size == 1) { - case cgltf_type_vec2: - size *= 2; - break; - case cgltf_type_vec3: - size *= 3; - break; - case cgltf_type_vec4: - size *= 4; - break; - case cgltf_type_mat2: - size *= 4; - break; - case cgltf_type_mat3: - size *= 9; - break; - case cgltf_type_mat4: - size *= 16; - break; - case cgltf_type_invalid: - case cgltf_type_scalar: - default: - size *= 1; - break; + return 8 * component_size; } - - return size; + else if (type == cgltf_type_mat3 && (component_size == 1 || component_size == 2)) + { + return 12 * component_size; + } + return component_size * cgltf_num_components(type); } static int cgltf_fixup_pointers(cgltf_data* out_data); @@ -3700,6 +4077,10 @@ static int cgltf_parse_json_root(cgltf_options* options, jsmntok_t const* tokens { i = cgltf_parse_json_animations(options, tokens, i + 1, json_chunk, out_data); } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_data->extras); + } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) { ++i; @@ -3743,7 +4124,7 @@ static int cgltf_parse_json_root(cgltf_options* options, jsmntok_t const* tokens } else { - i = cgltf_skip_json(tokens, i+1); + i = cgltf_skip_json(tokens, i + 1); } if (i < 0) @@ -3752,6 +4133,14 @@ static int cgltf_parse_json_root(cgltf_options* options, jsmntok_t const* tokens } } } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensionsUsed") == 0) + { + i = cgltf_parse_json_string_array(options, tokens, i + 1, json_chunk, &out_data->extensions_used, &out_data->extensions_used_count); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensionsRequired") == 0) + { + i = cgltf_parse_json_string_array(options, tokens, i + 1, json_chunk, &out_data->extensions_required, &out_data->extensions_required_count); + } else { i = cgltf_skip_json(tokens, i + 1); @@ -3768,7 +4157,7 @@ static int cgltf_parse_json_root(cgltf_options* options, jsmntok_t const* tokens cgltf_result cgltf_parse_json(cgltf_options* options, const uint8_t* json_chunk, cgltf_size size, cgltf_data** out_data) { - jsmn_parser parser = { 0 }; + jsmn_parser parser = { 0, 0, 0 }; if (options->json_token_count == 0) { @@ -3782,7 +4171,7 @@ cgltf_result cgltf_parse_json(cgltf_options* options, const uint8_t* json_chunk, options->json_token_count = token_count; } - jsmntok_t* tokens = (jsmntok_t*)options->memory_alloc(options->memory_user_data, sizeof(jsmntok_t) * options->json_token_count); + jsmntok_t* tokens = (jsmntok_t*)options->memory_alloc(options->memory_user_data, sizeof(jsmntok_t) * (options->json_token_count + 1)); if (!tokens) { @@ -3799,6 +4188,10 @@ cgltf_result cgltf_parse_json(cgltf_options* options, const uint8_t* json_chunk, return cgltf_result_invalid_json; } + // this makes sure that we always have an UNDEFINED token at the end of the stream + // for invalid JSON inputs this makes sure we don't perform out of bound reads of token data + tokens[token_count].type = JSMN_UNDEFINED; + cgltf_data* data = (cgltf_data*)options->memory_alloc(options->memory_user_data, sizeof(cgltf_data)); if (!data) @@ -3827,6 +4220,9 @@ cgltf_result cgltf_parse_json(cgltf_options* options, const uint8_t* json_chunk, return cgltf_result_invalid_gltf; } + data->json = (const char*)json_chunk; + data->json_size = size; + *out_data = data; return cgltf_result_success; diff --git a/src/external/dr_flac.h b/src/external/dr_flac.h index 13f42b2a8..250d0bd2e 100644 --- a/src/external/dr_flac.h +++ b/src/external/dr_flac.h @@ -1,6 +1,6 @@ /* FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file. -dr_flac - v0.11.7 - 2019-05-06 +dr_flac - v0.11.10 - 2019-06-26 David Reid - mackron@gmail.com */ @@ -149,7 +149,7 @@ typedef drflac_uint32 drflac_bool32; #elif (defined(__GNUC__) && __GNUC__ >= 4) /* GCC 4 */ #define DRFLAC_DEPRECATED __attribute__((deprecated)) #elif defined(__has_feature) /* Clang */ - #if defined(__has_feature(attribute_deprecated)) + #if __has_feature(attribute_deprecated) #define DRFLAC_DEPRECATED __attribute__((deprecated)) #else #define DRFLAC_DEPRECATED @@ -1008,7 +1008,7 @@ static DRFLAC_INLINE drflac_bool32 drflac_has_sse2() return DRFLAC_FALSE; #else int info[4]; - drflac_cpuid(info, 1); + drflac__cpuid(info, 1); return (info[3] & (1 << 26)) != 0; #endif #endif @@ -1033,7 +1033,7 @@ static DRFLAC_INLINE drflac_bool32 drflac_has_sse41() return DRFLAC_FALSE; #else int info[4]; - drflac_cpuid(info, 1); + drflac__cpuid(info, 1); return (info[2] & (1 << 19)) != 0; #endif #endif @@ -1141,21 +1141,43 @@ reference excess prior samples. /* CPU caps. */ static drflac_bool32 drflac__gIsLZCNTSupported = DRFLAC_FALSE; #ifndef DRFLAC_NO_CPUID +/* +I've had a bug report that Clang's ThreadSanitizer presents a warning in this function. Having reviewed this, this does +actually make sense. However, since CPU caps should never differ for a running process, I don't think the trade off of +complicating internal API's by passing around CPU caps versus just disabling the warnings is worthwhile. I'm therefore +just going to disable these warnings. +*/ +#if defined(__has_feature) + #if __has_feature(thread_sanitizer) + #define DRFLAC_NO_THREAD_SANITIZE __attribute__((no_sanitize("thread"))) + #else + #define DRFLAC_NO_THREAD_SANITIZE + #endif +#else + #define DRFLAC_NO_THREAD_SANITIZE +#endif static drflac_bool32 drflac__gIsSSE2Supported = DRFLAC_FALSE; static drflac_bool32 drflac__gIsSSE41Supported = DRFLAC_FALSE; -static void drflac__init_cpu_caps() +DRFLAC_NO_THREAD_SANITIZE static void drflac__init_cpu_caps() { - int info[4] = {0}; + static drflac_bool32 isCPUCapsInitialized = DRFLAC_FALSE; - /* LZCNT */ - drflac__cpuid(info, 0x80000001); - drflac__gIsLZCNTSupported = (info[2] & (1 << 5)) != 0; + if (!isCPUCapsInitialized) { + int info[4] = {0}; - /* SSE2 */ - drflac__gIsSSE2Supported = drflac_has_sse2(); + /* LZCNT */ + drflac__cpuid(info, 0x80000001); + drflac__gIsLZCNTSupported = (info[2] & (1 << 5)) != 0; - /* SSE4.1 */ - drflac__gIsSSE41Supported = drflac_has_sse41(); + /* SSE2 */ + drflac__gIsSSE2Supported = drflac_has_sse2(); + + /* SSE4.1 */ + drflac__gIsSSE41Supported = drflac_has_sse41(); + + /* Initialized. */ + isCPUCapsInitialized = DRFLAC_TRUE; + } } #endif @@ -4897,9 +4919,9 @@ typedef struct static DRFLAC_INLINE void drflac__decode_block_header(drflac_uint32 blockHeader, drflac_uint8* isLastBlock, drflac_uint8* blockType, drflac_uint32* blockSize) { blockHeader = drflac__be2host_32(blockHeader); - *isLastBlock = (blockHeader & (0x01 << 31)) >> 31; - *blockType = (blockHeader & (0x7F << 24)) >> 24; - *blockSize = (blockHeader & 0xFFFFFF); + *isLastBlock = (blockHeader & 0x80000000UL) >> 31; + *blockType = (blockHeader & 0x7F000000UL) >> 24; + *blockSize = (blockHeader & 0x00FFFFFFUL); } static 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) @@ -6759,10 +6781,10 @@ drflac_uint64 drflac__read_s32__misaligned(drflac* pFlac, drflac_uint64 samplesT case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE: { if (channelIndex == 0) { - decodedSample = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample; + decodedSample = (int)((drflac_uint32)pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample); } else { - int side = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample; - int left = pFlac->currentFrame.subframes[channelIndex - 1].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex - 1].wastedBitsPerSample; + int side = (int)((drflac_uint32)pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample); + int left = (int)((drflac_uint32)pFlac->currentFrame.subframes[channelIndex - 1].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex - 1].wastedBitsPerSample); decodedSample = left - side; } } break; @@ -6770,11 +6792,11 @@ drflac_uint64 drflac__read_s32__misaligned(drflac* pFlac, drflac_uint64 samplesT case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE: { if (channelIndex == 0) { - int side = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample; - int right = pFlac->currentFrame.subframes[channelIndex + 1].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 1].wastedBitsPerSample; + int side = (int)((drflac_uint32)pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample); + int right = (int)((drflac_uint32)pFlac->currentFrame.subframes[channelIndex + 1].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 1].wastedBitsPerSample); decodedSample = side + right; } else { - decodedSample = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample; + decodedSample = (int)((drflac_uint32)pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample); } } break; @@ -6783,14 +6805,14 @@ drflac_uint64 drflac__read_s32__misaligned(drflac* pFlac, drflac_uint64 samplesT int mid; int side; if (channelIndex == 0) { - mid = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample; - side = pFlac->currentFrame.subframes[channelIndex + 1].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 1].wastedBitsPerSample; + mid = (int)((drflac_uint32)pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample); + side = (int)((drflac_uint32)pFlac->currentFrame.subframes[channelIndex + 1].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 1].wastedBitsPerSample); mid = (((unsigned int)mid) << 1) | (side & 0x01); decodedSample = (mid + side) >> 1; } else { - mid = pFlac->currentFrame.subframes[channelIndex - 1].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex - 1].wastedBitsPerSample; - side = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample; + mid = (int)((drflac_uint32)pFlac->currentFrame.subframes[channelIndex - 1].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex - 1].wastedBitsPerSample); + side = (int)((drflac_uint32)pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample); mid = (((unsigned int)mid) << 1) | (side & 0x01); decodedSample = (mid - side) >> 1; @@ -6800,11 +6822,11 @@ drflac_uint64 drflac__read_s32__misaligned(drflac* pFlac, drflac_uint64 samplesT case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT: default: { - decodedSample = pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample; + decodedSample = (int)((drflac_uint32)pFlac->currentFrame.subframes[channelIndex + 0].pDecodedSamples[nextSampleInFrame] << pFlac->currentFrame.subframes[channelIndex + 0].wastedBitsPerSample); } break; } - decodedSample <<= (32 - pFlac->bitsPerSample); + decodedSample = (int)((drflac_uint32)decodedSample << (32 - pFlac->bitsPerSample)); if (bufferOut) { *bufferOut++ = decodedSample; @@ -6876,8 +6898,8 @@ drflac_uint64 drflac_read_s32(drflac* pFlac, drflac_uint64 samplesToRead, drflac const drflac_int32* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame; for (i = 0; i < alignedSampleCountPerChannel; ++i) { - int left = pDecodedSamples0[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample); - int side = pDecodedSamples1[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample); + int left = (int)((drflac_uint32)pDecodedSamples0[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample)); + int side = (int)((drflac_uint32)pDecodedSamples1[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample)); int right = left - side; bufferOut[i*2+0] = left; @@ -6892,8 +6914,8 @@ drflac_uint64 drflac_read_s32(drflac* pFlac, drflac_uint64 samplesToRead, drflac const drflac_int32* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame; for (i = 0; i < alignedSampleCountPerChannel; ++i) { - int side = pDecodedSamples0[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample); - int right = pDecodedSamples1[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample); + int side = (int)((drflac_uint32)pDecodedSamples0[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample)); + int right = (int)((drflac_uint32)pDecodedSamples1[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample)); int left = right + side; bufferOut[i*2+0] = left; @@ -6908,13 +6930,13 @@ drflac_uint64 drflac_read_s32(drflac* pFlac, drflac_uint64 samplesToRead, drflac const drflac_int32* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame; for (i = 0; i < alignedSampleCountPerChannel; ++i) { - int mid = pDecodedSamples0[i] << pFlac->currentFrame.subframes[0].wastedBitsPerSample; - int side = pDecodedSamples1[i] << pFlac->currentFrame.subframes[1].wastedBitsPerSample; + int mid = (int)((drflac_uint32)pDecodedSamples0[i] << pFlac->currentFrame.subframes[0].wastedBitsPerSample); + int side = (int)((drflac_uint32)pDecodedSamples1[i] << pFlac->currentFrame.subframes[1].wastedBitsPerSample); mid = (((drflac_uint32)mid) << 1) | (side & 0x01); - bufferOut[i*2+0] = ((mid + side) >> 1) << (unusedBitsPerSample); - bufferOut[i*2+1] = ((mid - side) >> 1) << (unusedBitsPerSample); + bufferOut[i*2+0] = (drflac_int32)((drflac_uint32)((mid + side) >> 1) << (unusedBitsPerSample)); + bufferOut[i*2+1] = (drflac_int32)((drflac_uint32)((mid - side) >> 1) << (unusedBitsPerSample)); } } break; @@ -6929,8 +6951,8 @@ drflac_uint64 drflac_read_s32(drflac* pFlac, drflac_uint64 samplesToRead, drflac const drflac_int32* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame; for (i = 0; i < alignedSampleCountPerChannel; ++i) { - bufferOut[i*2+0] = pDecodedSamples0[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample); - bufferOut[i*2+1] = pDecodedSamples1[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample); + bufferOut[i*2+0] = (drflac_int32)((drflac_uint32)pDecodedSamples0[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample)); + bufferOut[i*2+1] = (drflac_int32)((drflac_uint32)pDecodedSamples1[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample)); } } else @@ -6940,7 +6962,7 @@ drflac_uint64 drflac_read_s32(drflac* pFlac, drflac_uint64 samplesToRead, drflac for (i = 0; i < alignedSampleCountPerChannel; ++i) { unsigned int j; for (j = 0; j < channelCount; ++j) { - bufferOut[(i*channelCount)+j] = (pFlac->currentFrame.subframes[j].pDecodedSamples[firstAlignedSampleInFrame + i]) << (unusedBitsPerSample + pFlac->currentFrame.subframes[j].wastedBitsPerSample); + bufferOut[(i*channelCount)+j] = (drflac_int32)((drflac_uint32)(pFlac->currentFrame.subframes[j].pDecodedSamples[firstAlignedSampleInFrame + i]) << (unusedBitsPerSample + pFlac->currentFrame.subframes[j].wastedBitsPerSample)); } } } @@ -8649,6 +8671,15 @@ drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter, /* REVISION HISTORY ================ +v0.11.10 - 2019-06-26 + - Fix a compiler error. + +v0.11.9 - 2019-06-16 + - Silence some ThreadSanitizer warnings. + +v0.11.8 - 2019-05-21 + - Fix warnings. + v0.11.7 - 2019-05-06 - C89 fixes. diff --git a/src/external/dr_mp3.h b/src/external/dr_mp3.h index 26aeec56f..0ecd0d3f6 100644 --- a/src/external/dr_mp3.h +++ b/src/external/dr_mp3.h @@ -1,6 +1,6 @@ /* MP3 audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file. -dr_mp3 - v0.4.4 - 2019-05-06 +dr_mp3 - v0.4.7 - 2019-07-28 David Reid - mackron@gmail.com @@ -1143,41 +1143,72 @@ static void drmp3_L3_huffman(float *dst, drmp3_bs *bs, const drmp3_L3_gr_info *g int sfb_cnt = gr_info->region_count[ireg++]; const drmp3_int16 *codebook = tabs + tabindex[tab_num]; int linbits = g_linbits[tab_num]; - do + if (linbits) { - np = *sfb++ / 2; - pairs_to_decode = DRMP3_MIN(big_val_cnt, np); - one = *scf++; do { - int j, w = 5; - int leaf = codebook[DRMP3_PEEK_BITS(w)]; - while (leaf < 0) + np = *sfb++ / 2; + pairs_to_decode = DRMP3_MIN(big_val_cnt, np); + one = *scf++; + do { - DRMP3_FLUSH_BITS(w); - w = leaf & 7; - leaf = codebook[DRMP3_PEEK_BITS(w) - (leaf >> 3)]; - } - DRMP3_FLUSH_BITS(leaf >> 8); + int j, w = 5; + int leaf = codebook[DRMP3_PEEK_BITS(w)]; + while (leaf < 0) + { + DRMP3_FLUSH_BITS(w); + w = leaf & 7; + leaf = codebook[DRMP3_PEEK_BITS(w) - (leaf >> 3)]; + } + DRMP3_FLUSH_BITS(leaf >> 8); - for (j = 0; j < 2; j++, dst++, leaf >>= 4) + for (j = 0; j < 2; j++, dst++, leaf >>= 4) + { + int lsb = leaf & 0x0F; + if (lsb == 15) + { + lsb += DRMP3_PEEK_BITS(linbits); + DRMP3_FLUSH_BITS(linbits); + DRMP3_CHECK_BITS; + *dst = one*drmp3_L3_pow_43(lsb)*((drmp3_int32)bs_cache < 0 ? -1: 1); + } else + { + *dst = g_drmp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; + } + DRMP3_FLUSH_BITS(lsb ? 1 : 0); + } + DRMP3_CHECK_BITS; + } while (--pairs_to_decode); + } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0); + } else + { + do + { + np = *sfb++ / 2; + pairs_to_decode = DRMP3_MIN(big_val_cnt, np); + one = *scf++; + do { - int lsb = leaf & 0x0F; - if (lsb == 15 && linbits) + int j, w = 5; + int leaf = codebook[DRMP3_PEEK_BITS(w)]; + while (leaf < 0) { - lsb += DRMP3_PEEK_BITS(linbits); - DRMP3_FLUSH_BITS(linbits); - DRMP3_CHECK_BITS; - *dst = one*drmp3_L3_pow_43(lsb)*((drmp3_int32)bs_cache < 0 ? -1: 1); - } else + DRMP3_FLUSH_BITS(w); + w = leaf & 7; + leaf = codebook[DRMP3_PEEK_BITS(w) - (leaf >> 3)]; + } + DRMP3_FLUSH_BITS(leaf >> 8); + + for (j = 0; j < 2; j++, dst++, leaf >>= 4) { + int lsb = leaf & 0x0F; *dst = g_drmp3_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; + DRMP3_FLUSH_BITS(lsb ? 1 : 0); } - DRMP3_FLUSH_BITS(lsb ? 1 : 0); - } - DRMP3_CHECK_BITS; - } while (--pairs_to_decode); - } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0); + DRMP3_CHECK_BITS; + } while (--pairs_to_decode); + } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0); + } } for (np = 1 - big_val_cnt;; dst += 4) @@ -2133,14 +2164,14 @@ void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, int num_samples) int aligned_count = num_samples & ~7; for(; i < aligned_count; i+=8) { - static const drmp3_f4 g_scale = { 32768.0f, 32768.0f, 32768.0f, 32768.0f }; - drmp3_f4 a = DRMP3_VMUL(DRMP3_VLD(&in[i ]), g_scale); - drmp3_f4 b = DRMP3_VMUL(DRMP3_VLD(&in[i+4]), g_scale); + drmp3_f4 scale = DRMP3_VSET(32768.0f); + drmp3_f4 a = DRMP3_VMUL(DRMP3_VLD(&in[i ]), scale); + drmp3_f4 b = DRMP3_VMUL(DRMP3_VLD(&in[i+4]), scale); #if DRMP3_HAVE_SSE - static const drmp3_f4 g_max = { 32767.0f, 32767.0f, 32767.0f, 32767.0f }; - static const drmp3_f4 g_min = { -32768.0f, -32768.0f, -32768.0f, -32768.0f }; - __m128i pcm8 = _mm_packs_epi32(_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(a, g_max), g_min)), - _mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(b, g_max), g_min))); + drmp3_f4 s16max = DRMP3_VSET( 32767.0f); + drmp3_f4 s16min = DRMP3_VSET(-32768.0f); + __m128i pcm8 = _mm_packs_epi32(_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(a, s16max), s16min)), + _mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(b, s16max), s16min))); out[i ] = (drmp3_int16)_mm_extract_epi16(pcm8, 0); out[i+1] = (drmp3_int16)_mm_extract_epi16(pcm8, 1); out[i+2] = (drmp3_int16)_mm_extract_epi16(pcm8, 2); @@ -3779,6 +3810,15 @@ DIFFERENCES BETWEEN minimp3 AND dr_mp3 /* REVISION HISTORY ================ +v0.4.7 - 2019-07-28 + - Fix a compiler error. + +v0.4.6 - 2019-06-14 + - Fix a compiler error. + +v0.4.5 - 2019-06-06 + - Bring up to date with minimp3. + v0.4.4 - 2019-05-06 - Fixes to the VC6 build. diff --git a/src/external/dr_wav.h b/src/external/dr_wav.h index b2395bfb1..7c48ac400 100644 --- a/src/external/dr_wav.h +++ b/src/external/dr_wav.h @@ -1,6 +1,6 @@ /* WAV audio loader and writer. Choice of public domain or MIT-0. See license statements at the end of this file. -dr_wav - v0.9.1 - 2019-05-05 +dr_wav - v0.9.2 - 2019-05-21 David Reid - mackron@gmail.com */ @@ -2040,7 +2040,7 @@ drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc drwav_uint32 drwav_riff_chunk_size_riff(drwav_uint64 dataChunkSize) { - if (dataChunkSize <= (0xFFFFFFFF - 36)) { + if (dataChunkSize <= (0xFFFFFFFFUL - 36)) { return 36 + (drwav_uint32)dataChunkSize; } else { return 0xFFFFFFFF; @@ -2049,10 +2049,10 @@ drwav_uint32 drwav_riff_chunk_size_riff(drwav_uint64 dataChunkSize) drwav_uint32 drwav_data_chunk_size_riff(drwav_uint64 dataChunkSize) { - if (dataChunkSize <= 0xFFFFFFFF) { + if (dataChunkSize <= 0xFFFFFFFFUL) { return (drwav_uint32)dataChunkSize; } else { - return 0xFFFFFFFF; + return 0xFFFFFFFFUL; } } @@ -2121,7 +2121,7 @@ drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pF so for the sake of simplicity I'm not doing any validation for that. */ if (pFormat->container == drwav_container_riff) { - if (initialDataChunkSize > (0xFFFFFFFF - 36)) { + if (initialDataChunkSize > (0xFFFFFFFFUL - 36)) { return DRWAV_FALSE; /* Not enough room to store every sample. */ } } @@ -3195,8 +3195,8 @@ void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCou size_t i; for (i = 0; i < sampleCount; ++i) { int x = pIn[i]; - r = x - 128; - r = r << 8; + r = x << 8; + r = r - 32768; pOut[i] = (short)r; } } @@ -4675,6 +4675,9 @@ void drwav_free(void* pDataReturnedByOpenAndRead) /* REVISION HISTORY ================ +v0.9.2 - 2019-05-21 + - Fix warnings. + v0.9.1 - 2019-05-05 - Add support for C89. - Change license to choice of public domain or MIT-0. diff --git a/src/external/miniaudio.h b/src/external/miniaudio.h index f51a1b681..e6752fbf5 100644 --- a/src/external/miniaudio.h +++ b/src/external/miniaudio.h @@ -1,8 +1,10 @@ /* Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. -miniaudio (formerly mini_al) - v0.9.4 - 2019-05-06 +miniaudio (formerly mini_al) - v0.9.6 - 2019-xx-xx David Reid - davidreidsoftware@gmail.com + +https://github.com/dr-soft/miniaudio */ /* @@ -304,7 +306,7 @@ UWP Web Audio / Emscripten ---------------------- -- The first time a context is initialized it will create a global object called "mal" whose primary purpose is to act +- The first time a context is initialized it will create a global object called "miniaudio" whose primary purpose is to act as a factory for device objects. - Currently the Web Audio backend uses ScriptProcessorNode's, but this may need to change later as they've been deprecated. - Google is implementing a policy in their browsers that prevent automatic media output without first receiving some kind @@ -395,7 +397,7 @@ OPTIONS MA_LOG_LEVEL_WARNING MA_LOG_LEVEL_ERROR -#define MA_DEBUT_OUTPUT +#define MA_DEBUG_OUTPUT Enable printf() debug output. #define MA_COINIT_VALUE @@ -542,10 +544,10 @@ extern "C" { #endif #endif -typedef ma_uint8 ma_bool8; -typedef ma_uint32 ma_bool32; -#define MA_TRUE 1 -#define MA_FALSE 0 +typedef ma_uint8 ma_bool8; +typedef ma_uint32 ma_bool32; +#define MA_TRUE 1 +#define MA_FALSE 0 typedef void* ma_handle; typedef void* ma_ptr; @@ -944,7 +946,7 @@ MA_ALIGNED_STRUCT(MA_SIMD_ALIGNMENT) ma_src }; typedef struct ma_pcm_converter ma_pcm_converter; -typedef ma_uint32 (* ma_pcm_converter_read_proc)(ma_pcm_converter* pDSP, void* pSamplesOut, ma_uint32 frameCount, void* pUserData); +typedef ma_uint32 (* ma_pcm_converter_read_proc)(ma_pcm_converter* pDSP, void* pFramesOut, ma_uint32 frameCount, void* pUserData); typedef struct { @@ -987,7 +989,7 @@ MA_ALIGNED_STRUCT(MA_SIMD_ALIGNMENT) ma_pcm_converter ma_bool32 isChannelRoutingRequired : 1; ma_bool32 isSRCRequired : 1; ma_bool32 isChannelRoutingAtStart : 1; - ma_bool32 isPassthrough : 1; /* <-- Will be set to true when the DSP pipeline is an optimized passthrough. */ + ma_bool32 isPassthrough : 1; /* <-- Will be set to true when the conversion pipeline is an optimized passthrough. */ }; @@ -1342,7 +1344,7 @@ determine the required size of the output buffer. A return value of 0 indicates an error. -This function is useful for one-off bulk conversions, but if you're streaming data you should use the DSP APIs instead. +This function is useful for one-off bulk conversions, but if you're streaming data you should use the ma_pcm_converter APIs instead. */ ma_uint64 ma_convert_frames(void* pOut, ma_format formatOut, ma_uint32 channelsOut, ma_uint32 sampleRateOut, const void* pIn, ma_format formatIn, ma_uint32 channelsIn, ma_uint32 sampleRateIn, ma_uint64 frameCount); ma_uint64 ma_convert_frames_ex(void* pOut, ma_format formatOut, ma_uint32 channelsOut, ma_uint32 sampleRateOut, ma_channel channelMapOut[MA_MAX_CHANNELS], const void* pIn, ma_format formatIn, ma_uint32 channelsIn, ma_uint32 sampleRateIn, ma_channel channelMapIn[MA_MAX_CHANNELS], ma_uint64 frameCount); @@ -1770,7 +1772,9 @@ pInput is a pointer to a buffer containing input data from the device. This will null for a playback device. frameCount is the number of PCM frames to process. If an output buffer is provided (pOutput is not null), applications should write out -to the entire output buffer. +to the entire output buffer. Note that frameCount will not necessarily be exactly what you asked for when you initialized the deviced. +The bufferSizeInFrames and bufferSizeInMilliseconds members of the device config are just hints, and are not necessarily exactly what +you'll get. Do _not_ call any miniaudio APIs from the callback. Attempting the stop the device can result in a deadlock. The proper way to stop the device is to call ma_device_stop() from a different thread, normally the main application thread. @@ -2691,8 +2695,8 @@ Retrieves information about a device with the given ID. Do _not_ call this from within the ma_context_enumerate_devices() callback. -It's possible for a device to have different information and capabilities depending on wether or -not it's opened in shared or exclusive mode. For example, in shared mode, WASAPI always uses +It's possible for a device to have different information and capabilities depending on whether +or not it's opened in shared or exclusive mode. For example, in shared mode, WASAPI always uses floating point samples for mixing, but in exclusive mode it can be anything. Therefore, this function allows you to specify which share mode you want information for. Note that not all backends and devices support shared or exclusive mode, in which case this function will fail @@ -2723,7 +2727,8 @@ initialization of other devices. The device's configuration is controlled with pConfig. This allows you to configure the sample format, channel count, sample rate, etc. Before calling ma_device_init(), you will need to initialize a ma_device_config object using ma_device_config_init(). You must set the callback in -the device config. +the device config. Once initialized, the device's config is immutable. If you need to change the +config you will need to initialize a new device. Passing in 0 to any property in pConfig will force the use of a default value. In the case of sample format, channel count, sample rate and channel map it will default to the values used by @@ -2787,6 +2792,8 @@ Uninitializes a device. This will explicitly stop the device. You do not need to call ma_device_stop() beforehand, but it's harmless if you do. +Do not call this in any callback. + Return Value: MA_SUCCESS if successful; any other error code otherwise. @@ -2815,6 +2822,8 @@ to be done _before_ the device begins playback. This API waits until the backend device has been started for real by the worker thread. It also waits on a mutex for thread-safety. +Do not call this in any callback. + Return Value: MA_SUCCESS if successful; any other error code otherwise. @@ -2836,6 +2845,8 @@ the resuming it with ma_device_start() (which you might do when your program los in a situation where those samples are never output to the speakers or received from the microphone which can in turn result in de-syncs. +Do not call this in any callback. + Return Value: MA_SUCCESS if successful; any other error code otherwise. @@ -2990,10 +3001,11 @@ typedef enum ma_seek_origin_current } ma_seek_origin; -typedef size_t (* ma_decoder_read_proc) (ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead); /* Returns the number of bytes read. */ -typedef ma_bool32 (* ma_decoder_seek_proc) (ma_decoder* pDecoder, int byteOffset, ma_seek_origin origin); -typedef ma_result (* ma_decoder_seek_to_pcm_frame_proc)(ma_decoder* pDecoder, ma_uint64 frameIndex); -typedef ma_result (* ma_decoder_uninit_proc) (ma_decoder* pDecoder); +typedef size_t (* ma_decoder_read_proc) (ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead); /* Returns the number of bytes read. */ +typedef ma_bool32 (* ma_decoder_seek_proc) (ma_decoder* pDecoder, int byteOffset, ma_seek_origin origin); +typedef ma_result (* ma_decoder_seek_to_pcm_frame_proc) (ma_decoder* pDecoder, ma_uint64 frameIndex); +typedef ma_result (* ma_decoder_uninit_proc) (ma_decoder* pDecoder); +typedef ma_uint64 (* ma_decoder_get_length_in_pcm_frames_proc)(ma_decoder* pDecoder); typedef struct { @@ -3027,6 +3039,7 @@ struct ma_decoder ma_pcm_converter dsp; /* <-- Format conversion is achieved by running frames through this. */ ma_decoder_seek_to_pcm_frame_proc onSeekToPCMFrame; ma_decoder_uninit_proc onUninit; + ma_decoder_get_length_in_pcm_frames_proc onGetLengthInPCMFrames; void* pInternalDecoder; /* <-- The drwav/drflac/stb_vorbis/etc. objects. */ struct { @@ -3055,10 +3068,33 @@ ma_result ma_decoder_init_memory_raw(const void* pData, size_t dataSize, const m #ifndef MA_NO_STDIO ma_result ma_decoder_init_file(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); ma_result ma_decoder_init_file_wav(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +ma_result ma_decoder_init_file_flac(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +ma_result ma_decoder_init_file_vorbis(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +ma_result ma_decoder_init_file_mp3(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); + +ma_result ma_decoder_init_file_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +ma_result ma_decoder_init_file_wav_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +ma_result ma_decoder_init_file_flac_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +ma_result ma_decoder_init_file_vorbis_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); +ma_result ma_decoder_init_file_mp3_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder); #endif ma_result ma_decoder_uninit(ma_decoder* pDecoder); +/* +Retrieves the length of the decoder in PCM frames. + +Do not call this on streams of an undefined length, such as internet radio. + +If the length is unknown or an error occurs, 0 will be returned. + +This will always return 0 for Vorbis decoders. This is due to a limitation with stb_vorbis in push mode which is what miniaudio +uses internally. + +This will run in linear time for MP3 decoders. Do not call this in time critical scenarios. +*/ +ma_uint64 ma_decoder_get_length_in_pcm_frames(ma_decoder* pDecoder); + ma_uint64 ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount); ma_result ma_decoder_seek_to_pcm_frame(ma_decoder* pDecoder, ma_uint64 frameIndex); @@ -3192,7 +3228,7 @@ typedef struct tagBITMAPINFOHEADER { #endif #else -#include /* For malloc()/free() */ +#include /* For malloc(), free(), wcstombs(). */ #include /* For memset() */ #endif @@ -3345,7 +3381,7 @@ typedef struct tagBITMAPINFOHEADER { #define MA_NO_CPUID #endif - #if _MSC_VER >= 1600 + #if _MSC_VER >= 1600 && (defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 160040219) static MA_INLINE unsigned __int64 ma_xgetbv(int reg) { return _xgetbv(reg); @@ -3827,6 +3863,52 @@ int ma_strcat_s(char* dst, size_t dstSizeInBytes, const char* src) return 0; } +int ma_strncat_s(char* dst, size_t dstSizeInBytes, const char* src, size_t count) +{ + char* dstorig; + + if (dst == 0) { + return 22; + } + if (dstSizeInBytes == 0) { + return 34; + } + if (src == 0) { + return 22; + } + + dstorig = dst; + + while (dstSizeInBytes > 0 && dst[0] != '\0') { + dst += 1; + dstSizeInBytes -= 1; + } + + if (dstSizeInBytes == 0) { + return 22; /* Unterminated. */ + } + + + if (count == ((size_t)-1)) { /* _TRUNCATE */ + count = dstSizeInBytes - 1; + } + + while (dstSizeInBytes > 0 && src[0] != '\0' && count > 0) { + *dst++ = *src++; + dstSizeInBytes -= 1; + count -= 1; + } + + if (dstSizeInBytes > 0) { + dst[0] = '\0'; + } else { + dstorig[0] = '\0'; + return 34; + } + + return 0; +} + int ma_itoa_s(int value, char* dst, size_t dstSizeInBytes, int radix) { int sign; @@ -3919,6 +4001,23 @@ int ma_strcmp(const char* str1, const char* str2) return ((unsigned char*)str1)[0] - ((unsigned char*)str2)[0]; } +int ma_strappend(char* dst, size_t dstSize, const char* srcA, const char* srcB) +{ + int result; + + result = ma_strncpy_s(dst, dstSize, srcA, (size_t)-1); + if (result != 0) { + return result; + } + + result = ma_strncat_s(dst, dstSize, srcB, (size_t)-1); + if (result != 0) { + return result; + } + + return result; +} + char* ma_copy_string(const char* src) { size_t sz = strlen(src)+1; @@ -4383,6 +4482,63 @@ typedef LONG (WINAPI * MA_PFN_RegQueryValueExA)(HKEY hKey, LPCSTR lpValueName, L #define MA_DEFAULT_CAPTURE_DEVICE_NAME "Default Capture Device" +const char* ma_log_level_to_string(ma_uint32 logLevel) +{ + switch (logLevel) + { + case MA_LOG_LEVEL_VERBOSE: return ""; + case MA_LOG_LEVEL_INFO: return "INFO"; + case MA_LOG_LEVEL_WARNING: return "WARNING"; + case MA_LOG_LEVEL_ERROR: return "ERROR"; + default: return "ERROR"; + } +} + +/* Posts a log message. */ +void ma_log(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message) +{ + if (pContext == NULL) { + return; + } + +#if defined(MA_LOG_LEVEL) + if (logLevel <= MA_LOG_LEVEL) { + ma_log_proc onLog; + + #if defined(MA_DEBUG_OUTPUT) + if (logLevel <= MA_LOG_LEVEL) { + printf("%s: %s\n", ma_log_level_to_string(logLevel), message); + } + #endif + + onLog = pContext->logCallback; + if (onLog) { + onLog(pContext, pDevice, logLevel, message); + } + } +#endif +} + +/* Posts an log message. Throw a breakpoint in here if you're needing to debug. The return value is always "resultCode". */ +ma_result ma_context_post_error(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message, ma_result resultCode) +{ + /* Derive the context from the device if necessary. */ + if (pContext == NULL) { + if (pDevice != NULL) { + pContext = pDevice->pContext; + } + } + + ma_log(pContext, pDevice, logLevel, message); + return resultCode; +} + +ma_result ma_post_error(ma_device* pDevice, ma_uint32 logLevel, const char* message, ma_result resultCode) +{ + return ma_context_post_error(NULL, pDevice, logLevel, message, resultCode); +} + + /******************************************************************************* Timing @@ -4499,48 +4655,96 @@ double ma_timer_get_time_in_seconds(ma_timer* pTimer) Dynamic Linking *******************************************************************************/ -ma_handle ma_dlopen(const char* filename) +ma_handle ma_dlopen(ma_context* pContext, const char* filename) { + ma_handle handle; + +#if MA_LOG_LEVEL >= MA_LOG_LEVEL_VERBOSE + if (pContext != NULL) { + char message[256]; + ma_strappend(message, sizeof(message), "Loading library: ", filename); + ma_log(pContext, NULL, MA_LOG_LEVEL_VERBOSE, message); + } +#endif + #ifdef _WIN32 #ifdef MA_WIN32_DESKTOP - return (ma_handle)LoadLibraryA(filename); + handle = (ma_handle)LoadLibraryA(filename); #else /* *sigh* It appears there is no ANSI version of LoadPackagedLibrary()... */ WCHAR filenameW[4096]; if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, filenameW, sizeof(filenameW)) == 0) { - return NULL; + handle = NULL; + } else { + handle = (ma_handle)LoadPackagedLibrary(filenameW, 0); } - - return (ma_handle)LoadPackagedLibrary(filenameW, 0); #endif #else - return (ma_handle)dlopen(filename, RTLD_NOW); + handle = (ma_handle)dlopen(filename, RTLD_NOW); +#endif + + /* + I'm not considering failure to load a library an error nor a warning because seamlessly falling through to a lower-priority + backend is a deliberate design choice. Instead I'm logging it as an informational message. + */ +#if MA_LOG_LEVEL >= MA_LOG_LEVEL_INFO + if (handle == NULL) { + char message[256]; + ma_strappend(message, sizeof(message), "Failed to load library: ", filename); + ma_log(pContext, NULL, MA_LOG_LEVEL_INFO, message); + } #endif + + (void)pContext; /* It's possible for pContext to be unused. */ + return handle; } -void ma_dlclose(ma_handle handle) +void ma_dlclose(ma_context* pContext, ma_handle handle) { #ifdef _WIN32 FreeLibrary((HMODULE)handle); #else dlclose((void*)handle); #endif + + (void)pContext; } -ma_proc ma_dlsym(ma_handle handle, const char* symbol) +ma_proc ma_dlsym(ma_context* pContext, ma_handle handle, const char* symbol) { + ma_proc proc; + +#if MA_LOG_LEVEL >= MA_LOG_LEVEL_VERBOSE + if (pContext != NULL) { + char message[256]; + ma_strappend(message, sizeof(message), "Loading symbol: ", symbol); + ma_log(pContext, NULL, MA_LOG_LEVEL_VERBOSE, message); + } +#endif + #ifdef _WIN32 - return (ma_proc)GetProcAddress((HMODULE)handle, symbol); + proc = (ma_proc)GetProcAddress((HMODULE)handle, symbol); #else #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" #endif - return (ma_proc)dlsym((void*)handle, symbol); + proc = (ma_proc)dlsym((void*)handle, symbol); #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) #pragma GCC diagnostic pop #endif #endif + +#if MA_LOG_LEVEL >= MA_LOG_LEVEL_WARNING + if (handle == NULL) { + char message[256]; + ma_strappend(message, sizeof(message), "Failed to load symbol: ", symbol); + ma_log(pContext, NULL, MA_LOG_LEVEL_WARNING, message); + } +#endif + + (void)pContext; /* It's possible for pContext to be unused. */ + return proc; } @@ -4560,7 +4764,7 @@ int ma_thread_priority_to_win32(ma_thread_priority priority) case ma_thread_priority_high: return THREAD_PRIORITY_ABOVE_NORMAL; case ma_thread_priority_highest: return THREAD_PRIORITY_HIGHEST; case ma_thread_priority_realtime: return THREAD_PRIORITY_TIME_CRITICAL; - default: return ma_thread_priority_normal; + default: return THREAD_PRIORITY_NORMAL; } } @@ -5102,63 +5306,6 @@ void ma_zero_pcm_frames(void* p, ma_uint32 frameCount, ma_format format, ma_uint } -const char* ma_log_level_to_string(ma_uint32 logLevel) -{ - switch (logLevel) - { - case MA_LOG_LEVEL_VERBOSE: return ""; - case MA_LOG_LEVEL_INFO: return "INFO"; - case MA_LOG_LEVEL_WARNING: return "WARNING"; - case MA_LOG_LEVEL_ERROR: return "ERROR"; - default: return "ERROR"; - } -} - -/* Posts a log message. */ -void ma_log(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message) -{ - if (pContext == NULL) { - return; - } - -#if defined(MA_LOG_LEVEL) - if (logLevel <= MA_LOG_LEVEL) { - ma_log_proc onLog; - - #if defined(MA_DEBUG_OUTPUT) - if (logLevel <= MA_LOG_LEVEL) { - printf("%s: %s\n", ma_log_level_to_string(logLevel), message); - } - #endif - - onLog = pContext->logCallback; - if (onLog) { - onLog(pContext, pDevice, logLevel, message); - } - } -#endif -} - -/* Posts an error. Throw a breakpoint in here if you're needing to debug. The return value is always "resultCode". */ -ma_result ma_context_post_error(ma_context* pContext, ma_device* pDevice, ma_uint32 logLevel, const char* message, ma_result resultCode) -{ - /* Derive the context from the device if necessary. */ - if (pContext == NULL) { - if (pDevice != NULL) { - pContext = pDevice->pContext; - } - } - - ma_log(pContext, pDevice, logLevel, message); - return resultCode; -} - -ma_result ma_post_error(ma_device* pDevice, ma_uint32 logLevel, const char* message, ma_result resultCode) -{ - return ma_context_post_error(NULL, pDevice, logLevel, message, resultCode); -} - - /* The callback for reading from the client -> DSP -> device. */ ma_uint32 ma_device__on_read_from_client(ma_pcm_converter* pDSP, void* pFramesOut, ma_uint32 frameCount, void* pUserData) @@ -5421,13 +5568,10 @@ static MA_INLINE void ma_device__set_state(ma_device* pDevice, ma_uint32 newStat /* A helper for getting the state of the device. */ static MA_INLINE ma_uint32 ma_device__get_state(ma_device* pDevice) { - return pDevice->state; -} + ma_uint32 state; + ma_atomic_exchange_32(&state, pDevice->state); -/* A helper for determining whether or not the device is running in async mode. */ -static MA_INLINE ma_bool32 ma_device__is_async(ma_device* pDevice) -{ - return pDevice->onData != NULL; + return state; } @@ -7116,6 +7260,8 @@ ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context* pCont ma_IPropertyStore_Release(pProperties); return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve device format for device info retrieval.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } + + ma_IPropertyStore_Release(pProperties); } else { return ma_context_post_error(pContext, NULL, MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to open property store for device info retrieval.", MA_FAILED_TO_OPEN_BACKEND_DEVICE); } @@ -7578,6 +7724,8 @@ ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device_type d clientProperties.eCategory = MA_AudioCategory_Other; ma_IAudioClient2_SetClientProperties(pAudioClient2, &clientProperties); } + + pAudioClient2->lpVtbl->Release(pAudioClient2); } @@ -7688,7 +7836,7 @@ ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device_type d } if (hr == MA_AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED) { - UINT bufferSizeInFrames; + ma_uint32 bufferSizeInFrames; hr = ma_IAudioClient_GetBufferSize((ma_IAudioClient*)pData->pAudioClient, &bufferSizeInFrames); if (SUCCEEDED(hr)) { bufferDuration = (MA_REFERENCE_TIME)((10000.0 * 1000 / wf.Format.nSamplesPerSec * bufferSizeInFrames) + 0.5); @@ -8744,7 +8892,6 @@ ma_result ma_context_init__wasapi(const ma_context_config* pConfig, ma_context* ma_assert(pContext != NULL); - (void)pContext; (void)pConfig; #ifdef MA_WIN32_DESKTOP @@ -8760,15 +8907,15 @@ ma_result ma_context_init__wasapi(const ma_context_config* pConfig, ma_context* ma_PFNVerifyVersionInfoW _VerifyVersionInfoW; ma_PFNVerSetConditionMask _VerSetConditionMask; - kernel32DLL = ma_dlopen("kernel32.dll"); + kernel32DLL = ma_dlopen(pContext, "kernel32.dll"); if (kernel32DLL == NULL) { return MA_NO_BACKEND; } - _VerifyVersionInfoW = (ma_PFNVerifyVersionInfoW)ma_dlsym(kernel32DLL, "VerifyVersionInfoW"); - _VerSetConditionMask = (ma_PFNVerSetConditionMask)ma_dlsym(kernel32DLL, "VerSetConditionMask"); + _VerifyVersionInfoW = (ma_PFNVerifyVersionInfoW)ma_dlsym(pContext, kernel32DLL, "VerifyVersionInfoW"); + _VerSetConditionMask = (ma_PFNVerSetConditionMask)ma_dlsym(pContext, kernel32DLL, "VerSetConditionMask"); if (_VerifyVersionInfoW == NULL || _VerSetConditionMask == NULL) { - ma_dlclose(kernel32DLL); + ma_dlclose(pContext, kernel32DLL); return MA_NO_BACKEND; } @@ -8783,7 +8930,7 @@ ma_result ma_context_init__wasapi(const ma_context_config* pConfig, ma_context* result = MA_NO_BACKEND; } - ma_dlclose(kernel32DLL); + ma_dlclose(pContext, kernel32DLL); } #endif @@ -10436,7 +10583,7 @@ ma_result ma_context_uninit__dsound(ma_context* pContext) ma_assert(pContext != NULL); ma_assert(pContext->backend == ma_backend_dsound); - ma_dlclose(pContext->dsound.hDSoundDLL); + ma_dlclose(pContext, pContext->dsound.hDSoundDLL); return MA_SUCCESS; } @@ -10447,15 +10594,15 @@ ma_result ma_context_init__dsound(const ma_context_config* pConfig, ma_context* (void)pConfig; - pContext->dsound.hDSoundDLL = ma_dlopen("dsound.dll"); + pContext->dsound.hDSoundDLL = ma_dlopen(pContext, "dsound.dll"); if (pContext->dsound.hDSoundDLL == NULL) { return MA_API_NOT_FOUND; } - pContext->dsound.DirectSoundCreate = ma_dlsym(pContext->dsound.hDSoundDLL, "DirectSoundCreate"); - pContext->dsound.DirectSoundEnumerateA = ma_dlsym(pContext->dsound.hDSoundDLL, "DirectSoundEnumerateA"); - pContext->dsound.DirectSoundCaptureCreate = ma_dlsym(pContext->dsound.hDSoundDLL, "DirectSoundCaptureCreate"); - pContext->dsound.DirectSoundCaptureEnumerateA = ma_dlsym(pContext->dsound.hDSoundDLL, "DirectSoundCaptureEnumerateA"); + pContext->dsound.DirectSoundCreate = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCreate"); + pContext->dsound.DirectSoundEnumerateA = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundEnumerateA"); + pContext->dsound.DirectSoundCaptureCreate = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCaptureCreate"); + pContext->dsound.DirectSoundCaptureEnumerateA = ma_dlsym(pContext, pContext->dsound.hDSoundDLL, "DirectSoundCaptureEnumerateA"); pContext->onUninit = ma_context_uninit__dsound; pContext->onDeviceIDEqual = ma_context_is_device_id_equal__dsound; @@ -11454,7 +11601,7 @@ ma_result ma_context_uninit__winmm(ma_context* pContext) ma_assert(pContext != NULL); ma_assert(pContext->backend == ma_backend_winmm); - ma_dlclose(pContext->winmm.hWinMM); + ma_dlclose(pContext, pContext->winmm.hWinMM); return MA_SUCCESS; } @@ -11464,28 +11611,28 @@ ma_result ma_context_init__winmm(const ma_context_config* pConfig, ma_context* p (void)pConfig; - pContext->winmm.hWinMM = ma_dlopen("winmm.dll"); + pContext->winmm.hWinMM = ma_dlopen(pContext, "winmm.dll"); if (pContext->winmm.hWinMM == NULL) { return MA_NO_BACKEND; } - pContext->winmm.waveOutGetNumDevs = ma_dlsym(pContext->winmm.hWinMM, "waveOutGetNumDevs"); - pContext->winmm.waveOutGetDevCapsA = ma_dlsym(pContext->winmm.hWinMM, "waveOutGetDevCapsA"); - pContext->winmm.waveOutOpen = ma_dlsym(pContext->winmm.hWinMM, "waveOutOpen"); - pContext->winmm.waveOutClose = ma_dlsym(pContext->winmm.hWinMM, "waveOutClose"); - pContext->winmm.waveOutPrepareHeader = ma_dlsym(pContext->winmm.hWinMM, "waveOutPrepareHeader"); - pContext->winmm.waveOutUnprepareHeader = ma_dlsym(pContext->winmm.hWinMM, "waveOutUnprepareHeader"); - pContext->winmm.waveOutWrite = ma_dlsym(pContext->winmm.hWinMM, "waveOutWrite"); - pContext->winmm.waveOutReset = ma_dlsym(pContext->winmm.hWinMM, "waveOutReset"); - pContext->winmm.waveInGetNumDevs = ma_dlsym(pContext->winmm.hWinMM, "waveInGetNumDevs"); - pContext->winmm.waveInGetDevCapsA = ma_dlsym(pContext->winmm.hWinMM, "waveInGetDevCapsA"); - pContext->winmm.waveInOpen = ma_dlsym(pContext->winmm.hWinMM, "waveInOpen"); - pContext->winmm.waveInClose = ma_dlsym(pContext->winmm.hWinMM, "waveInClose"); - pContext->winmm.waveInPrepareHeader = ma_dlsym(pContext->winmm.hWinMM, "waveInPrepareHeader"); - pContext->winmm.waveInUnprepareHeader = ma_dlsym(pContext->winmm.hWinMM, "waveInUnprepareHeader"); - pContext->winmm.waveInAddBuffer = ma_dlsym(pContext->winmm.hWinMM, "waveInAddBuffer"); - pContext->winmm.waveInStart = ma_dlsym(pContext->winmm.hWinMM, "waveInStart"); - pContext->winmm.waveInReset = ma_dlsym(pContext->winmm.hWinMM, "waveInReset"); + pContext->winmm.waveOutGetNumDevs = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutGetNumDevs"); + pContext->winmm.waveOutGetDevCapsA = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutGetDevCapsA"); + pContext->winmm.waveOutOpen = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutOpen"); + pContext->winmm.waveOutClose = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutClose"); + pContext->winmm.waveOutPrepareHeader = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutPrepareHeader"); + pContext->winmm.waveOutUnprepareHeader = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutUnprepareHeader"); + pContext->winmm.waveOutWrite = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutWrite"); + pContext->winmm.waveOutReset = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveOutReset"); + pContext->winmm.waveInGetNumDevs = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInGetNumDevs"); + pContext->winmm.waveInGetDevCapsA = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInGetDevCapsA"); + pContext->winmm.waveInOpen = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInOpen"); + pContext->winmm.waveInClose = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInClose"); + pContext->winmm.waveInPrepareHeader = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInPrepareHeader"); + pContext->winmm.waveInUnprepareHeader = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInUnprepareHeader"); + pContext->winmm.waveInAddBuffer = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInAddBuffer"); + pContext->winmm.waveInStart = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInStart"); + pContext->winmm.waveInReset = ma_dlsym(pContext, pContext->winmm.hWinMM, "waveInReset"); pContext->onUninit = ma_context_uninit__winmm; pContext->onDeviceIDEqual = ma_context_is_device_id_equal__winmm; @@ -13261,14 +13408,29 @@ ma_result ma_device_stop__alsa(ma_device* pDevice) if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { ((ma_snd_pcm_drain_proc)pDevice->pContext->alsa.snd_pcm_drain)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture); + + /* We need to prepare the device again, otherwise we won't be able to restart the device. */ + if (((ma_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)((ma_snd_pcm_t*)pDevice->alsa.pPCMCapture) < 0) { + #ifdef MA_DEBUG_OUTPUT + printf("[ALSA] Failed to prepare capture device after stopping.\n"); + #endif + } } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { /* Using drain instead of drop because ma_device_stop() is defined such that pending frames are processed before returning. */ ((ma_snd_pcm_drain_proc)pDevice->pContext->alsa.snd_pcm_drain)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback); + + /* We need to prepare the device again, otherwise we won't be able to restart the device. */ + if (((ma_snd_pcm_prepare_proc)pDevice->pContext->alsa.snd_pcm_prepare)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback) < 0) { + #ifdef MA_DEBUG_OUTPUT + printf("[ALSA] Failed to prepare playback device after stopping.\n"); + #endif + } } + return MA_SUCCESS; } @@ -13415,7 +13577,7 @@ ma_result ma_context_uninit__alsa(ma_context* pContext) ((ma_snd_config_update_free_global_proc)pContext->alsa.snd_config_update_free_global)(); #ifndef MA_NO_RUNTIME_LINKING - ma_dlclose(pContext->alsa.asoundSO); + ma_dlclose(pContext, pContext->alsa.asoundSO); #endif ma_mutex_uninit(&pContext->alsa.internalDeviceEnumLock); @@ -13433,7 +13595,7 @@ ma_result ma_context_init__alsa(const ma_context_config* pConfig, ma_context* pC size_t i; for (i = 0; i < ma_countof(libasoundNames); ++i) { - pContext->alsa.asoundSO = ma_dlopen(libasoundNames[i]); + pContext->alsa.asoundSO = ma_dlopen(pContext, libasoundNames[i]); if (pContext->alsa.asoundSO != NULL) { break; } @@ -13446,61 +13608,61 @@ ma_result ma_context_init__alsa(const ma_context_config* pConfig, ma_context* pC return MA_NO_BACKEND; } - pContext->alsa.snd_pcm_open = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_open"); - pContext->alsa.snd_pcm_close = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_close"); - pContext->alsa.snd_pcm_hw_params_sizeof = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_sizeof"); - pContext->alsa.snd_pcm_hw_params_any = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_any"); - pContext->alsa.snd_pcm_hw_params_set_format = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_set_format"); - pContext->alsa.snd_pcm_hw_params_set_format_first = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_set_format_first"); - pContext->alsa.snd_pcm_hw_params_get_format_mask = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_get_format_mask"); - pContext->alsa.snd_pcm_hw_params_set_channels_near = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_set_channels_near"); - pContext->alsa.snd_pcm_hw_params_set_rate_resample = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_set_rate_resample"); - pContext->alsa.snd_pcm_hw_params_set_rate_near = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_set_rate_near"); - pContext->alsa.snd_pcm_hw_params_set_buffer_size_near = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_set_buffer_size_near"); - pContext->alsa.snd_pcm_hw_params_set_periods_near = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_set_periods_near"); - pContext->alsa.snd_pcm_hw_params_set_access = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_set_access"); - pContext->alsa.snd_pcm_hw_params_get_format = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_get_format"); - pContext->alsa.snd_pcm_hw_params_get_channels = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels"); - pContext->alsa.snd_pcm_hw_params_get_channels_min = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels_min"); - pContext->alsa.snd_pcm_hw_params_get_channels_max = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels_max"); - pContext->alsa.snd_pcm_hw_params_get_rate = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate"); - pContext->alsa.snd_pcm_hw_params_get_rate_min = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate_min"); - pContext->alsa.snd_pcm_hw_params_get_rate_max = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate_max"); - pContext->alsa.snd_pcm_hw_params_get_buffer_size = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_get_buffer_size"); - pContext->alsa.snd_pcm_hw_params_get_periods = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_get_periods"); - pContext->alsa.snd_pcm_hw_params_get_access = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params_get_access"); - pContext->alsa.snd_pcm_hw_params = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_hw_params"); - pContext->alsa.snd_pcm_sw_params_sizeof = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_sw_params_sizeof"); - pContext->alsa.snd_pcm_sw_params_current = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_sw_params_current"); - pContext->alsa.snd_pcm_sw_params_get_boundary = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_sw_params_get_boundary"); - pContext->alsa.snd_pcm_sw_params_set_avail_min = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_sw_params_set_avail_min"); - pContext->alsa.snd_pcm_sw_params_set_start_threshold = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_sw_params_set_start_threshold"); - pContext->alsa.snd_pcm_sw_params_set_stop_threshold = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_sw_params_set_stop_threshold"); - pContext->alsa.snd_pcm_sw_params = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_sw_params"); - pContext->alsa.snd_pcm_format_mask_sizeof = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_format_mask_sizeof"); - pContext->alsa.snd_pcm_format_mask_test = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_format_mask_test"); - pContext->alsa.snd_pcm_get_chmap = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_get_chmap"); - pContext->alsa.snd_pcm_state = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_state"); - pContext->alsa.snd_pcm_prepare = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_prepare"); - pContext->alsa.snd_pcm_start = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_start"); - pContext->alsa.snd_pcm_drop = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_drop"); - pContext->alsa.snd_pcm_drain = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_drain"); - pContext->alsa.snd_device_name_hint = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_device_name_hint"); - pContext->alsa.snd_device_name_get_hint = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_device_name_get_hint"); - pContext->alsa.snd_card_get_index = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_card_get_index"); - pContext->alsa.snd_device_name_free_hint = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_device_name_free_hint"); - pContext->alsa.snd_pcm_mmap_begin = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_mmap_begin"); - pContext->alsa.snd_pcm_mmap_commit = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_mmap_commit"); - pContext->alsa.snd_pcm_recover = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_recover"); - pContext->alsa.snd_pcm_readi = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_readi"); - pContext->alsa.snd_pcm_writei = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_writei"); - pContext->alsa.snd_pcm_avail = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_avail"); - pContext->alsa.snd_pcm_avail_update = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_avail_update"); - pContext->alsa.snd_pcm_wait = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_wait"); - pContext->alsa.snd_pcm_info = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_info"); - pContext->alsa.snd_pcm_info_sizeof = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_info_sizeof"); - pContext->alsa.snd_pcm_info_get_name = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_pcm_info_get_name"); - pContext->alsa.snd_config_update_free_global = (ma_proc)ma_dlsym(pContext->alsa.asoundSO, "snd_config_update_free_global"); + pContext->alsa.snd_pcm_open = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_open"); + pContext->alsa.snd_pcm_close = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_close"); + pContext->alsa.snd_pcm_hw_params_sizeof = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_sizeof"); + pContext->alsa.snd_pcm_hw_params_any = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_any"); + pContext->alsa.snd_pcm_hw_params_set_format = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_format"); + pContext->alsa.snd_pcm_hw_params_set_format_first = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_format_first"); + pContext->alsa.snd_pcm_hw_params_get_format_mask = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_format_mask"); + pContext->alsa.snd_pcm_hw_params_set_channels_near = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_channels_near"); + pContext->alsa.snd_pcm_hw_params_set_rate_resample = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_rate_resample"); + pContext->alsa.snd_pcm_hw_params_set_rate_near = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_rate_near"); + pContext->alsa.snd_pcm_hw_params_set_buffer_size_near = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_buffer_size_near"); + pContext->alsa.snd_pcm_hw_params_set_periods_near = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_periods_near"); + pContext->alsa.snd_pcm_hw_params_set_access = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_set_access"); + pContext->alsa.snd_pcm_hw_params_get_format = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_format"); + pContext->alsa.snd_pcm_hw_params_get_channels = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels"); + pContext->alsa.snd_pcm_hw_params_get_channels_min = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels_min"); + pContext->alsa.snd_pcm_hw_params_get_channels_max = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_channels_max"); + pContext->alsa.snd_pcm_hw_params_get_rate = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate"); + pContext->alsa.snd_pcm_hw_params_get_rate_min = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate_min"); + pContext->alsa.snd_pcm_hw_params_get_rate_max = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_rate_max"); + pContext->alsa.snd_pcm_hw_params_get_buffer_size = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_buffer_size"); + pContext->alsa.snd_pcm_hw_params_get_periods = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_periods"); + pContext->alsa.snd_pcm_hw_params_get_access = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params_get_access"); + pContext->alsa.snd_pcm_hw_params = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_hw_params"); + pContext->alsa.snd_pcm_sw_params_sizeof = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_sizeof"); + pContext->alsa.snd_pcm_sw_params_current = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_current"); + pContext->alsa.snd_pcm_sw_params_get_boundary = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_get_boundary"); + pContext->alsa.snd_pcm_sw_params_set_avail_min = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_set_avail_min"); + pContext->alsa.snd_pcm_sw_params_set_start_threshold = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_set_start_threshold"); + pContext->alsa.snd_pcm_sw_params_set_stop_threshold = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params_set_stop_threshold"); + pContext->alsa.snd_pcm_sw_params = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_sw_params"); + pContext->alsa.snd_pcm_format_mask_sizeof = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_format_mask_sizeof"); + pContext->alsa.snd_pcm_format_mask_test = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_format_mask_test"); + pContext->alsa.snd_pcm_get_chmap = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_get_chmap"); + pContext->alsa.snd_pcm_state = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_state"); + pContext->alsa.snd_pcm_prepare = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_prepare"); + pContext->alsa.snd_pcm_start = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_start"); + pContext->alsa.snd_pcm_drop = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_drop"); + pContext->alsa.snd_pcm_drain = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_drain"); + pContext->alsa.snd_device_name_hint = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_device_name_hint"); + pContext->alsa.snd_device_name_get_hint = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_device_name_get_hint"); + pContext->alsa.snd_card_get_index = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_card_get_index"); + pContext->alsa.snd_device_name_free_hint = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_device_name_free_hint"); + pContext->alsa.snd_pcm_mmap_begin = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_mmap_begin"); + pContext->alsa.snd_pcm_mmap_commit = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_mmap_commit"); + pContext->alsa.snd_pcm_recover = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_recover"); + pContext->alsa.snd_pcm_readi = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_readi"); + pContext->alsa.snd_pcm_writei = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_writei"); + pContext->alsa.snd_pcm_avail = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_avail"); + pContext->alsa.snd_pcm_avail_update = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_avail_update"); + pContext->alsa.snd_pcm_wait = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_wait"); + pContext->alsa.snd_pcm_info = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_info"); + pContext->alsa.snd_pcm_info_sizeof = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_info_sizeof"); + pContext->alsa.snd_pcm_info_get_name = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_pcm_info_get_name"); + pContext->alsa.snd_config_update_free_global = (ma_proc)ma_dlsym(pContext, pContext->alsa.asoundSO, "snd_config_update_free_global"); #else /* The system below is just for type safety. */ ma_snd_pcm_open_proc _snd_pcm_open = snd_pcm_open; @@ -14830,7 +14992,7 @@ ma_pa_buffer_attr ma_device__pa_buffer_attr_new(ma_uint32 bufferSizeInFrames, ma attr.maxlength = bufferSizeInFrames * ma_get_bytes_per_sample(ma_format_from_pulse(ss->format)) * ss->channels; attr.tlength = attr.maxlength / periods; attr.prebuf = (ma_uint32)-1; - attr.minreq = attr.maxlength / periods; + attr.minreq = (ma_uint32)-1; attr.fragsize = attr.maxlength / periods; return attr; @@ -15481,7 +15643,7 @@ ma_result ma_context_uninit__pulse(ma_context* pContext) pContext->pulse.pApplicationName = NULL; #ifndef MA_NO_RUNTIME_LINKING - ma_dlclose(pContext->pulse.pulseSO); + ma_dlclose(pContext, pContext->pulse.pulseSO); #endif return MA_SUCCESS; @@ -15497,7 +15659,7 @@ ma_result ma_context_init__pulse(const ma_context_config* pConfig, ma_context* p size_t i; for (i = 0; i < ma_countof(libpulseNames); ++i) { - pContext->pulse.pulseSO = ma_dlopen(libpulseNames[i]); + pContext->pulse.pulseSO = ma_dlopen(pContext, libpulseNames[i]); if (pContext->pulse.pulseSO != NULL) { break; } @@ -15507,50 +15669,50 @@ ma_result ma_context_init__pulse(const ma_context_config* pConfig, ma_context* p return MA_NO_BACKEND; } - pContext->pulse.pa_mainloop_new = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_mainloop_new"); - pContext->pulse.pa_mainloop_free = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_mainloop_free"); - pContext->pulse.pa_mainloop_get_api = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_mainloop_get_api"); - pContext->pulse.pa_mainloop_iterate = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_mainloop_iterate"); - pContext->pulse.pa_mainloop_wakeup = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_mainloop_wakeup"); - pContext->pulse.pa_context_new = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_context_new"); - pContext->pulse.pa_context_unref = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_context_unref"); - pContext->pulse.pa_context_connect = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_context_connect"); - pContext->pulse.pa_context_disconnect = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_context_disconnect"); - pContext->pulse.pa_context_set_state_callback = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_context_set_state_callback"); - pContext->pulse.pa_context_get_state = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_context_get_state"); - pContext->pulse.pa_context_get_sink_info_list = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_context_get_sink_info_list"); - pContext->pulse.pa_context_get_source_info_list = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_context_get_source_info_list"); - pContext->pulse.pa_context_get_sink_info_by_name = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_context_get_sink_info_by_name"); - pContext->pulse.pa_context_get_source_info_by_name = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_context_get_source_info_by_name"); - pContext->pulse.pa_operation_unref = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_operation_unref"); - pContext->pulse.pa_operation_get_state = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_operation_get_state"); - pContext->pulse.pa_channel_map_init_extend = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_channel_map_init_extend"); - pContext->pulse.pa_channel_map_valid = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_channel_map_valid"); - pContext->pulse.pa_channel_map_compatible = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_channel_map_compatible"); - pContext->pulse.pa_stream_new = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_stream_new"); - pContext->pulse.pa_stream_unref = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_stream_unref"); - pContext->pulse.pa_stream_connect_playback = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_stream_connect_playback"); - pContext->pulse.pa_stream_connect_record = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_stream_connect_record"); - pContext->pulse.pa_stream_disconnect = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_stream_disconnect"); - pContext->pulse.pa_stream_get_state = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_stream_get_state"); - pContext->pulse.pa_stream_get_sample_spec = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_stream_get_sample_spec"); - pContext->pulse.pa_stream_get_channel_map = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_stream_get_channel_map"); - pContext->pulse.pa_stream_get_buffer_attr = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_stream_get_buffer_attr"); - pContext->pulse.pa_stream_set_buffer_attr = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_stream_set_buffer_attr"); - pContext->pulse.pa_stream_get_device_name = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_stream_get_device_name"); - pContext->pulse.pa_stream_set_write_callback = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_stream_set_write_callback"); - pContext->pulse.pa_stream_set_read_callback = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_stream_set_read_callback"); - pContext->pulse.pa_stream_flush = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_stream_flush"); - pContext->pulse.pa_stream_drain = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_stream_drain"); - pContext->pulse.pa_stream_is_corked = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_stream_is_corked"); - pContext->pulse.pa_stream_cork = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_stream_cork"); - pContext->pulse.pa_stream_trigger = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_stream_trigger"); - pContext->pulse.pa_stream_begin_write = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_stream_begin_write"); - pContext->pulse.pa_stream_write = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_stream_write"); - pContext->pulse.pa_stream_peek = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_stream_peek"); - pContext->pulse.pa_stream_drop = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_stream_drop"); - pContext->pulse.pa_stream_writable_size = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_stream_writable_size"); - pContext->pulse.pa_stream_readable_size = (ma_proc)ma_dlsym(pContext->pulse.pulseSO, "pa_stream_readable_size"); + pContext->pulse.pa_mainloop_new = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_new"); + pContext->pulse.pa_mainloop_free = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_free"); + pContext->pulse.pa_mainloop_get_api = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_get_api"); + pContext->pulse.pa_mainloop_iterate = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_iterate"); + pContext->pulse.pa_mainloop_wakeup = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_mainloop_wakeup"); + pContext->pulse.pa_context_new = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_new"); + pContext->pulse.pa_context_unref = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_unref"); + pContext->pulse.pa_context_connect = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_connect"); + pContext->pulse.pa_context_disconnect = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_disconnect"); + pContext->pulse.pa_context_set_state_callback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_set_state_callback"); + pContext->pulse.pa_context_get_state = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_state"); + pContext->pulse.pa_context_get_sink_info_list = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_sink_info_list"); + pContext->pulse.pa_context_get_source_info_list = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_source_info_list"); + pContext->pulse.pa_context_get_sink_info_by_name = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_sink_info_by_name"); + pContext->pulse.pa_context_get_source_info_by_name = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_context_get_source_info_by_name"); + pContext->pulse.pa_operation_unref = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_operation_unref"); + pContext->pulse.pa_operation_get_state = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_operation_get_state"); + pContext->pulse.pa_channel_map_init_extend = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_channel_map_init_extend"); + pContext->pulse.pa_channel_map_valid = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_channel_map_valid"); + pContext->pulse.pa_channel_map_compatible = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_channel_map_compatible"); + pContext->pulse.pa_stream_new = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_new"); + pContext->pulse.pa_stream_unref = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_unref"); + pContext->pulse.pa_stream_connect_playback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_connect_playback"); + pContext->pulse.pa_stream_connect_record = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_connect_record"); + pContext->pulse.pa_stream_disconnect = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_disconnect"); + pContext->pulse.pa_stream_get_state = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_state"); + pContext->pulse.pa_stream_get_sample_spec = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_sample_spec"); + pContext->pulse.pa_stream_get_channel_map = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_channel_map"); + pContext->pulse.pa_stream_get_buffer_attr = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_buffer_attr"); + pContext->pulse.pa_stream_set_buffer_attr = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_buffer_attr"); + pContext->pulse.pa_stream_get_device_name = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_get_device_name"); + pContext->pulse.pa_stream_set_write_callback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_write_callback"); + pContext->pulse.pa_stream_set_read_callback = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_set_read_callback"); + pContext->pulse.pa_stream_flush = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_flush"); + pContext->pulse.pa_stream_drain = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_drain"); + pContext->pulse.pa_stream_is_corked = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_is_corked"); + pContext->pulse.pa_stream_cork = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_cork"); + pContext->pulse.pa_stream_trigger = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_trigger"); + pContext->pulse.pa_stream_begin_write = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_begin_write"); + pContext->pulse.pa_stream_write = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_write"); + pContext->pulse.pa_stream_peek = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_peek"); + pContext->pulse.pa_stream_drop = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_drop"); + pContext->pulse.pa_stream_writable_size = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_writable_size"); + pContext->pulse.pa_stream_readable_size = (ma_proc)ma_dlsym(pContext, pContext->pulse.pulseSO, "pa_stream_readable_size"); #else /* This strange assignment system is just for type safety. */ ma_pa_mainloop_new_proc _pa_mainloop_new = pa_mainloop_new; @@ -15678,7 +15840,7 @@ ma_result ma_context_init__pulse(const ma_context_config* pConfig, ma_context* p ma_free(pContext->pulse.pServerName); ma_free(pContext->pulse.pApplicationName); #ifndef MA_NO_RUNTIME_LINKING - ma_dlclose(pContext->pulse.pulseSO); + ma_dlclose(pContext, pContext->pulse.pulseSO); #endif return MA_NO_BACKEND; } @@ -15689,7 +15851,7 @@ ma_result ma_context_init__pulse(const ma_context_config* pConfig, ma_context* p ma_free(pContext->pulse.pApplicationName); ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop); #ifndef MA_NO_RUNTIME_LINKING - ma_dlclose(pContext->pulse.pulseSO); + ma_dlclose(pContext, pContext->pulse.pulseSO); #endif return MA_NO_BACKEND; } @@ -15700,7 +15862,7 @@ ma_result ma_context_init__pulse(const ma_context_config* pConfig, ma_context* p ma_free(pContext->pulse.pApplicationName); ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop); #ifndef MA_NO_RUNTIME_LINKING - ma_dlclose(pContext->pulse.pulseSO); + ma_dlclose(pContext, pContext->pulse.pulseSO); #endif return MA_NO_BACKEND; } @@ -15712,7 +15874,7 @@ ma_result ma_context_init__pulse(const ma_context_config* pConfig, ma_context* p ((ma_pa_context_unref_proc)pContext->pulse.pa_context_unref)(pPulseContext); ((ma_pa_mainloop_free_proc)pContext->pulse.pa_mainloop_free)(pMainLoop); #ifndef MA_NO_RUNTIME_LINKING - ma_dlclose(pContext->pulse.pulseSO); + ma_dlclose(pContext, pContext->pulse.pulseSO); #endif return MA_NO_BACKEND; } @@ -16253,7 +16415,7 @@ ma_result ma_context_uninit__jack(ma_context* pContext) pContext->jack.pClientName = NULL; #ifndef MA_NO_RUNTIME_LINKING - ma_dlclose(pContext->jack.jackSO); + ma_dlclose(pContext, pContext->jack.jackSO); #endif return MA_SUCCESS; @@ -16273,7 +16435,7 @@ ma_result ma_context_init__jack(const ma_context_config* pConfig, ma_context* pC size_t i; for (i = 0; i < ma_countof(libjackNames); ++i) { - pContext->jack.jackSO = ma_dlopen(libjackNames[i]); + pContext->jack.jackSO = ma_dlopen(pContext, libjackNames[i]); if (pContext->jack.jackSO != NULL) { break; } @@ -16283,22 +16445,22 @@ ma_result ma_context_init__jack(const ma_context_config* pConfig, ma_context* pC return MA_NO_BACKEND; } - pContext->jack.jack_client_open = (ma_proc)ma_dlsym(pContext->jack.jackSO, "jack_client_open"); - pContext->jack.jack_client_close = (ma_proc)ma_dlsym(pContext->jack.jackSO, "jack_client_close"); - pContext->jack.jack_client_name_size = (ma_proc)ma_dlsym(pContext->jack.jackSO, "jack_client_name_size"); - pContext->jack.jack_set_process_callback = (ma_proc)ma_dlsym(pContext->jack.jackSO, "jack_set_process_callback"); - pContext->jack.jack_set_buffer_size_callback = (ma_proc)ma_dlsym(pContext->jack.jackSO, "jack_set_buffer_size_callback"); - pContext->jack.jack_on_shutdown = (ma_proc)ma_dlsym(pContext->jack.jackSO, "jack_on_shutdown"); - pContext->jack.jack_get_sample_rate = (ma_proc)ma_dlsym(pContext->jack.jackSO, "jack_get_sample_rate"); - pContext->jack.jack_get_buffer_size = (ma_proc)ma_dlsym(pContext->jack.jackSO, "jack_get_buffer_size"); - pContext->jack.jack_get_ports = (ma_proc)ma_dlsym(pContext->jack.jackSO, "jack_get_ports"); - pContext->jack.jack_activate = (ma_proc)ma_dlsym(pContext->jack.jackSO, "jack_activate"); - pContext->jack.jack_deactivate = (ma_proc)ma_dlsym(pContext->jack.jackSO, "jack_deactivate"); - pContext->jack.jack_connect = (ma_proc)ma_dlsym(pContext->jack.jackSO, "jack_connect"); - pContext->jack.jack_port_register = (ma_proc)ma_dlsym(pContext->jack.jackSO, "jack_port_register"); - pContext->jack.jack_port_name = (ma_proc)ma_dlsym(pContext->jack.jackSO, "jack_port_name"); - pContext->jack.jack_port_get_buffer = (ma_proc)ma_dlsym(pContext->jack.jackSO, "jack_port_get_buffer"); - pContext->jack.jack_free = (ma_proc)ma_dlsym(pContext->jack.jackSO, "jack_free"); + pContext->jack.jack_client_open = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_client_open"); + pContext->jack.jack_client_close = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_client_close"); + pContext->jack.jack_client_name_size = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_client_name_size"); + pContext->jack.jack_set_process_callback = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_set_process_callback"); + pContext->jack.jack_set_buffer_size_callback = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_set_buffer_size_callback"); + pContext->jack.jack_on_shutdown = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_on_shutdown"); + pContext->jack.jack_get_sample_rate = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_get_sample_rate"); + pContext->jack.jack_get_buffer_size = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_get_buffer_size"); + pContext->jack.jack_get_ports = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_get_ports"); + pContext->jack.jack_activate = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_activate"); + pContext->jack.jack_deactivate = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_deactivate"); + pContext->jack.jack_connect = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_connect"); + pContext->jack.jack_port_register = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_port_register"); + pContext->jack.jack_port_name = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_port_name"); + pContext->jack.jack_port_get_buffer = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_port_get_buffer"); + pContext->jack.jack_free = (ma_proc)ma_dlsym(pContext, pContext->jack.jackSO, "jack_free"); #else /* This strange assignment system is here just to ensure type safety of miniaudio's function pointer @@ -16365,7 +16527,7 @@ ma_result ma_context_init__jack(const ma_context_config* pConfig, ma_context* pC if (result != MA_SUCCESS) { ma_free(pContext->jack.pClientName); #ifndef MA_NO_RUNTIME_LINKING - ma_dlclose(pContext->jack.jackSO); + ma_dlclose(pContext, pContext->jack.jackSO); #endif return MA_NO_BACKEND; } @@ -18793,9 +18955,9 @@ ma_result ma_context_uninit__coreaudio(ma_context* pContext) ma_assert(pContext->backend == ma_backend_coreaudio); #if !defined(MA_NO_RUNTIME_LINKING) && !defined(MA_APPLE_MOBILE) - ma_dlclose(pContext->coreaudio.hAudioUnit); - ma_dlclose(pContext->coreaudio.hCoreAudio); - ma_dlclose(pContext->coreaudio.hCoreFoundation); + ma_dlclose(pContext, pContext->coreaudio.hAudioUnit); + ma_dlclose(pContext, pContext->coreaudio.hCoreAudio); + ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation); #endif (void)pContext; @@ -18824,24 +18986,24 @@ ma_result ma_context_init__coreaudio(const ma_context_config* pConfig, ma_contex #endif #if !defined(MA_NO_RUNTIME_LINKING) && !defined(MA_APPLE_MOBILE) - pContext->coreaudio.hCoreFoundation = ma_dlopen("CoreFoundation.framework/CoreFoundation"); + pContext->coreaudio.hCoreFoundation = ma_dlopen(pContext, "CoreFoundation.framework/CoreFoundation"); if (pContext->coreaudio.hCoreFoundation == NULL) { return MA_API_NOT_FOUND; } - pContext->coreaudio.CFStringGetCString = ma_dlsym(pContext->coreaudio.hCoreFoundation, "CFStringGetCString"); + pContext->coreaudio.CFStringGetCString = ma_dlsym(pContext, pContext->coreaudio.hCoreFoundation, "CFStringGetCString"); - pContext->coreaudio.hCoreAudio = ma_dlopen("CoreAudio.framework/CoreAudio"); + pContext->coreaudio.hCoreAudio = ma_dlopen(pContext, "CoreAudio.framework/CoreAudio"); if (pContext->coreaudio.hCoreAudio == NULL) { - ma_dlclose(pContext->coreaudio.hCoreFoundation); + ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation); return MA_API_NOT_FOUND; } - pContext->coreaudio.AudioObjectGetPropertyData = ma_dlsym(pContext->coreaudio.hCoreAudio, "AudioObjectGetPropertyData"); - pContext->coreaudio.AudioObjectGetPropertyDataSize = ma_dlsym(pContext->coreaudio.hCoreAudio, "AudioObjectGetPropertyDataSize"); - pContext->coreaudio.AudioObjectSetPropertyData = ma_dlsym(pContext->coreaudio.hCoreAudio, "AudioObjectSetPropertyData"); - pContext->coreaudio.AudioObjectAddPropertyListener = ma_dlsym(pContext->coreaudio.hCoreAudio, "AudioObjectAddPropertyListener"); + pContext->coreaudio.AudioObjectGetPropertyData = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectGetPropertyData"); + pContext->coreaudio.AudioObjectGetPropertyDataSize = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectGetPropertyDataSize"); + pContext->coreaudio.AudioObjectSetPropertyData = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectSetPropertyData"); + pContext->coreaudio.AudioObjectAddPropertyListener = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectAddPropertyListener"); /* It looks like Apple has moved some APIs from AudioUnit into AudioToolbox on more recent versions of macOS. They are still @@ -18849,35 +19011,35 @@ ma_result ma_context_init__coreaudio(const ma_context_config* pConfig, ma_contex The way it'll work is that it'll first try AudioUnit, and if the required symbols are not present there we'll fall back to AudioToolbox. */ - pContext->coreaudio.hAudioUnit = ma_dlopen("AudioUnit.framework/AudioUnit"); + pContext->coreaudio.hAudioUnit = ma_dlopen(pContext, "AudioUnit.framework/AudioUnit"); if (pContext->coreaudio.hAudioUnit == NULL) { - ma_dlclose(pContext->coreaudio.hCoreAudio); - ma_dlclose(pContext->coreaudio.hCoreFoundation); + ma_dlclose(pContext, pContext->coreaudio.hCoreAudio); + ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation); return MA_API_NOT_FOUND; } - if (ma_dlsym(pContext->coreaudio.hAudioUnit, "AudioComponentFindNext") == NULL) { + if (ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentFindNext") == NULL) { /* Couldn't find the required symbols in AudioUnit, so fall back to AudioToolbox. */ - ma_dlclose(pContext->coreaudio.hAudioUnit); - pContext->coreaudio.hAudioUnit = ma_dlopen("AudioToolbox.framework/AudioToolbox"); + ma_dlclose(pContext, pContext->coreaudio.hAudioUnit); + pContext->coreaudio.hAudioUnit = ma_dlopen(pContext, "AudioToolbox.framework/AudioToolbox"); if (pContext->coreaudio.hAudioUnit == NULL) { - ma_dlclose(pContext->coreaudio.hCoreAudio); - ma_dlclose(pContext->coreaudio.hCoreFoundation); + ma_dlclose(pContext, pContext->coreaudio.hCoreAudio); + ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation); return MA_API_NOT_FOUND; } } - pContext->coreaudio.AudioComponentFindNext = ma_dlsym(pContext->coreaudio.hAudioUnit, "AudioComponentFindNext"); - pContext->coreaudio.AudioComponentInstanceDispose = ma_dlsym(pContext->coreaudio.hAudioUnit, "AudioComponentInstanceDispose"); - pContext->coreaudio.AudioComponentInstanceNew = ma_dlsym(pContext->coreaudio.hAudioUnit, "AudioComponentInstanceNew"); - pContext->coreaudio.AudioOutputUnitStart = ma_dlsym(pContext->coreaudio.hAudioUnit, "AudioOutputUnitStart"); - pContext->coreaudio.AudioOutputUnitStop = ma_dlsym(pContext->coreaudio.hAudioUnit, "AudioOutputUnitStop"); - pContext->coreaudio.AudioUnitAddPropertyListener = ma_dlsym(pContext->coreaudio.hAudioUnit, "AudioUnitAddPropertyListener"); - pContext->coreaudio.AudioUnitGetPropertyInfo = ma_dlsym(pContext->coreaudio.hAudioUnit, "AudioUnitGetPropertyInfo"); - pContext->coreaudio.AudioUnitGetProperty = ma_dlsym(pContext->coreaudio.hAudioUnit, "AudioUnitGetProperty"); - pContext->coreaudio.AudioUnitSetProperty = ma_dlsym(pContext->coreaudio.hAudioUnit, "AudioUnitSetProperty"); - pContext->coreaudio.AudioUnitInitialize = ma_dlsym(pContext->coreaudio.hAudioUnit, "AudioUnitInitialize"); - pContext->coreaudio.AudioUnitRender = ma_dlsym(pContext->coreaudio.hAudioUnit, "AudioUnitRender"); + pContext->coreaudio.AudioComponentFindNext = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentFindNext"); + pContext->coreaudio.AudioComponentInstanceDispose = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentInstanceDispose"); + pContext->coreaudio.AudioComponentInstanceNew = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentInstanceNew"); + pContext->coreaudio.AudioOutputUnitStart = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioOutputUnitStart"); + pContext->coreaudio.AudioOutputUnitStop = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioOutputUnitStop"); + pContext->coreaudio.AudioUnitAddPropertyListener = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitAddPropertyListener"); + pContext->coreaudio.AudioUnitGetPropertyInfo = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitGetPropertyInfo"); + pContext->coreaudio.AudioUnitGetProperty = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitGetProperty"); + pContext->coreaudio.AudioUnitSetProperty = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitSetProperty"); + pContext->coreaudio.AudioUnitInitialize = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitInitialize"); + pContext->coreaudio.AudioUnitRender = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitRender"); #else pContext->coreaudio.CFStringGetCString = (ma_proc)CFStringGetCString; @@ -18928,9 +19090,9 @@ ma_result ma_context_init__coreaudio(const ma_context_config* pConfig, ma_contex pContext->coreaudio.component = ((ma_AudioComponentFindNext_proc)pContext->coreaudio.AudioComponentFindNext)(NULL, &desc); if (pContext->coreaudio.component == NULL) { #if !defined(MA_NO_RUNTIME_LINKING) && !defined(MA_APPLE_MOBILE) - ma_dlclose(pContext->coreaudio.hAudioUnit); - ma_dlclose(pContext->coreaudio.hCoreAudio); - ma_dlclose(pContext->coreaudio.hCoreFoundation); + ma_dlclose(pContext, pContext->coreaudio.hAudioUnit); + ma_dlclose(pContext, pContext->coreaudio.hCoreAudio); + ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation); #endif return MA_FAILED_TO_INIT_BACKEND; } @@ -19734,7 +19896,7 @@ ma_result ma_context_init__sndio(const ma_context_config* pConfig, ma_context* p size_t i; for (i = 0; i < ma_countof(libsndioNames); ++i) { - pContext->sndio.sndioSO = ma_dlopen(libsndioNames[i]); + pContext->sndio.sndioSO = ma_dlopen(pContext, libsndioNames[i]); if (pContext->sndio.sndioSO != NULL) { break; } @@ -19744,16 +19906,16 @@ ma_result ma_context_init__sndio(const ma_context_config* pConfig, ma_context* p return MA_NO_BACKEND; } - pContext->sndio.sio_open = (ma_proc)ma_dlsym(pContext->sndio.sndioSO, "sio_open"); - pContext->sndio.sio_close = (ma_proc)ma_dlsym(pContext->sndio.sndioSO, "sio_close"); - pContext->sndio.sio_setpar = (ma_proc)ma_dlsym(pContext->sndio.sndioSO, "sio_setpar"); - pContext->sndio.sio_getpar = (ma_proc)ma_dlsym(pContext->sndio.sndioSO, "sio_getpar"); - pContext->sndio.sio_getcap = (ma_proc)ma_dlsym(pContext->sndio.sndioSO, "sio_getcap"); - pContext->sndio.sio_write = (ma_proc)ma_dlsym(pContext->sndio.sndioSO, "sio_write"); - pContext->sndio.sio_read = (ma_proc)ma_dlsym(pContext->sndio.sndioSO, "sio_read"); - pContext->sndio.sio_start = (ma_proc)ma_dlsym(pContext->sndio.sndioSO, "sio_start"); - pContext->sndio.sio_stop = (ma_proc)ma_dlsym(pContext->sndio.sndioSO, "sio_stop"); - pContext->sndio.sio_initpar = (ma_proc)ma_dlsym(pContext->sndio.sndioSO, "sio_initpar"); + pContext->sndio.sio_open = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_open"); + pContext->sndio.sio_close = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_close"); + pContext->sndio.sio_setpar = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_setpar"); + pContext->sndio.sio_getpar = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_getpar"); + pContext->sndio.sio_getcap = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_getcap"); + pContext->sndio.sio_write = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_write"); + pContext->sndio.sio_read = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_read"); + pContext->sndio.sio_start = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_start"); + pContext->sndio.sio_stop = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_stop"); + pContext->sndio.sio_initpar = (ma_proc)ma_dlsym(pContext, pContext->sndio.sndioSO, "sio_initpar"); #else pContext->sndio.sio_open = sio_open; pContext->sndio.sio_close = sio_close; @@ -21625,7 +21787,7 @@ ma_result ma_context_uninit__aaudio(ma_context* pContext) ma_assert(pContext != NULL); ma_assert(pContext->backend == ma_backend_aaudio); - ma_dlclose(pContext->aaudio.hAAudio); + ma_dlclose(pContext, pContext->aaudio.hAAudio); pContext->aaudio.hAAudio = NULL; return MA_SUCCESS; @@ -21639,7 +21801,7 @@ ma_result ma_context_init__aaudio(const ma_context_config* pConfig, ma_context* size_t i; for (i = 0; i < ma_countof(libNames); ++i) { - pContext->aaudio.hAAudio = ma_dlopen(libNames[i]); + pContext->aaudio.hAAudio = ma_dlopen(pContext, libNames[i]); if (pContext->aaudio.hAAudio != NULL) { break; } @@ -21649,30 +21811,30 @@ ma_result ma_context_init__aaudio(const ma_context_config* pConfig, ma_context* return MA_FAILED_TO_INIT_BACKEND; } - pContext->aaudio.AAudio_createStreamBuilder = (ma_proc)ma_dlsym(pContext->aaudio.hAAudio, "AAudio_createStreamBuilder"); - pContext->aaudio.AAudioStreamBuilder_delete = (ma_proc)ma_dlsym(pContext->aaudio.hAAudio, "AAudioStreamBuilder_delete"); - pContext->aaudio.AAudioStreamBuilder_setDeviceId = (ma_proc)ma_dlsym(pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDeviceId"); - pContext->aaudio.AAudioStreamBuilder_setDirection = (ma_proc)ma_dlsym(pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDirection"); - pContext->aaudio.AAudioStreamBuilder_setSharingMode = (ma_proc)ma_dlsym(pContext->aaudio.hAAudio, "AAudioStreamBuilder_setSharingMode"); - pContext->aaudio.AAudioStreamBuilder_setFormat = (ma_proc)ma_dlsym(pContext->aaudio.hAAudio, "AAudioStreamBuilder_setFormat"); - pContext->aaudio.AAudioStreamBuilder_setChannelCount = (ma_proc)ma_dlsym(pContext->aaudio.hAAudio, "AAudioStreamBuilder_setChannelCount"); - pContext->aaudio.AAudioStreamBuilder_setSampleRate = (ma_proc)ma_dlsym(pContext->aaudio.hAAudio, "AAudioStreamBuilder_setSampleRate"); - pContext->aaudio.AAudioStreamBuilder_setBufferCapacityInFrames = (ma_proc)ma_dlsym(pContext->aaudio.hAAudio, "AAudioStreamBuilder_setBufferCapacityInFrames"); - pContext->aaudio.AAudioStreamBuilder_setFramesPerDataCallback = (ma_proc)ma_dlsym(pContext->aaudio.hAAudio, "AAudioStreamBuilder_setFramesPerDataCallback"); - pContext->aaudio.AAudioStreamBuilder_setDataCallback = (ma_proc)ma_dlsym(pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDataCallback"); - pContext->aaudio.AAudioStreamBuilder_setPerformanceMode = (ma_proc)ma_dlsym(pContext->aaudio.hAAudio, "AAudioStreamBuilder_setPerformanceMode"); - pContext->aaudio.AAudioStreamBuilder_openStream = (ma_proc)ma_dlsym(pContext->aaudio.hAAudio, "AAudioStreamBuilder_openStream"); - pContext->aaudio.AAudioStream_close = (ma_proc)ma_dlsym(pContext->aaudio.hAAudio, "AAudioStream_close"); - pContext->aaudio.AAudioStream_getState = (ma_proc)ma_dlsym(pContext->aaudio.hAAudio, "AAudioStream_getState"); - pContext->aaudio.AAudioStream_waitForStateChange = (ma_proc)ma_dlsym(pContext->aaudio.hAAudio, "AAudioStream_waitForStateChange"); - pContext->aaudio.AAudioStream_getFormat = (ma_proc)ma_dlsym(pContext->aaudio.hAAudio, "AAudioStream_getFormat"); - pContext->aaudio.AAudioStream_getChannelCount = (ma_proc)ma_dlsym(pContext->aaudio.hAAudio, "AAudioStream_getChannelCount"); - pContext->aaudio.AAudioStream_getSampleRate = (ma_proc)ma_dlsym(pContext->aaudio.hAAudio, "AAudioStream_getSampleRate"); - pContext->aaudio.AAudioStream_getBufferCapacityInFrames = (ma_proc)ma_dlsym(pContext->aaudio.hAAudio, "AAudioStream_getBufferCapacityInFrames"); - pContext->aaudio.AAudioStream_getFramesPerDataCallback = (ma_proc)ma_dlsym(pContext->aaudio.hAAudio, "AAudioStream_getFramesPerDataCallback"); - pContext->aaudio.AAudioStream_getFramesPerBurst = (ma_proc)ma_dlsym(pContext->aaudio.hAAudio, "AAudioStream_getFramesPerBurst"); - pContext->aaudio.AAudioStream_requestStart = (ma_proc)ma_dlsym(pContext->aaudio.hAAudio, "AAudioStream_requestStart"); - pContext->aaudio.AAudioStream_requestStop = (ma_proc)ma_dlsym(pContext->aaudio.hAAudio, "AAudioStream_requestStop"); + pContext->aaudio.AAudio_createStreamBuilder = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudio_createStreamBuilder"); + pContext->aaudio.AAudioStreamBuilder_delete = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_delete"); + pContext->aaudio.AAudioStreamBuilder_setDeviceId = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDeviceId"); + pContext->aaudio.AAudioStreamBuilder_setDirection = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDirection"); + pContext->aaudio.AAudioStreamBuilder_setSharingMode = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setSharingMode"); + pContext->aaudio.AAudioStreamBuilder_setFormat = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setFormat"); + pContext->aaudio.AAudioStreamBuilder_setChannelCount = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setChannelCount"); + pContext->aaudio.AAudioStreamBuilder_setSampleRate = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setSampleRate"); + pContext->aaudio.AAudioStreamBuilder_setBufferCapacityInFrames = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setBufferCapacityInFrames"); + pContext->aaudio.AAudioStreamBuilder_setFramesPerDataCallback = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setFramesPerDataCallback"); + pContext->aaudio.AAudioStreamBuilder_setDataCallback = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setDataCallback"); + pContext->aaudio.AAudioStreamBuilder_setPerformanceMode = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_setPerformanceMode"); + pContext->aaudio.AAudioStreamBuilder_openStream = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStreamBuilder_openStream"); + pContext->aaudio.AAudioStream_close = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_close"); + pContext->aaudio.AAudioStream_getState = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getState"); + pContext->aaudio.AAudioStream_waitForStateChange = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_waitForStateChange"); + pContext->aaudio.AAudioStream_getFormat = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getFormat"); + pContext->aaudio.AAudioStream_getChannelCount = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getChannelCount"); + pContext->aaudio.AAudioStream_getSampleRate = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getSampleRate"); + pContext->aaudio.AAudioStream_getBufferCapacityInFrames = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getBufferCapacityInFrames"); + pContext->aaudio.AAudioStream_getFramesPerDataCallback = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getFramesPerDataCallback"); + pContext->aaudio.AAudioStream_getFramesPerBurst = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_getFramesPerBurst"); + pContext->aaudio.AAudioStream_requestStart = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_requestStart"); + pContext->aaudio.AAudioStream_requestStop = (ma_proc)ma_dlsym(pContext, pContext->aaudio.hAAudio, "AAudioStream_requestStop"); pContext->isBackendAsynchronous = MA_TRUE; @@ -22522,7 +22684,7 @@ ma_result ma_device_start__opensl(ma_device* pDevice) periodSizeInBytes = (pDevice->capture.internalBufferSizeInFrames / pDevice->capture.internalPeriods) * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels); for (iPeriod = 0; iPeriod < pDevice->capture.internalPeriods; ++iPeriod) { - resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture, pDevice->opensl.pBufferCapture + (periodSizeInBytes * iPeriod), periodSizeInBytes); + resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture, pDevice->opensl.pBufferCapture + (periodSizeInBytes * iPeriod), periodSizeInBytes); if (resultSL != SL_RESULT_SUCCESS) { MA_OPENSL_RECORD(pDevice->opensl.pAudioRecorder)->SetRecordState((SLRecordItf)pDevice->opensl.pAudioRecorder, SL_RECORDSTATE_STOPPED); return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "[OpenSL] Failed to enqueue buffer for capture device.", MA_FAILED_TO_START_BACKEND_DEVICE); @@ -23594,9 +23756,9 @@ ma_bool32 ma_device__is_initialized(ma_device* pDevice) ma_result ma_context_uninit_backend_apis__win32(ma_context* pContext) { ma_CoUninitialize(pContext); - ma_dlclose(pContext->win32.hUser32DLL); - ma_dlclose(pContext->win32.hOle32DLL); - ma_dlclose(pContext->win32.hAdvapi32DLL); + ma_dlclose(pContext, pContext->win32.hUser32DLL); + ma_dlclose(pContext, pContext->win32.hOle32DLL); + ma_dlclose(pContext, pContext->win32.hAdvapi32DLL); return MA_SUCCESS; } @@ -23605,38 +23767,38 @@ ma_result ma_context_init_backend_apis__win32(ma_context* pContext) { #ifdef MA_WIN32_DESKTOP /* Ole32.dll */ - pContext->win32.hOle32DLL = ma_dlopen("ole32.dll"); + pContext->win32.hOle32DLL = ma_dlopen(pContext, "ole32.dll"); if (pContext->win32.hOle32DLL == NULL) { return MA_FAILED_TO_INIT_BACKEND; } - pContext->win32.CoInitializeEx = (ma_proc)ma_dlsym(pContext->win32.hOle32DLL, "CoInitializeEx"); - pContext->win32.CoUninitialize = (ma_proc)ma_dlsym(pContext->win32.hOle32DLL, "CoUninitialize"); - pContext->win32.CoCreateInstance = (ma_proc)ma_dlsym(pContext->win32.hOle32DLL, "CoCreateInstance"); - pContext->win32.CoTaskMemFree = (ma_proc)ma_dlsym(pContext->win32.hOle32DLL, "CoTaskMemFree"); - pContext->win32.PropVariantClear = (ma_proc)ma_dlsym(pContext->win32.hOle32DLL, "PropVariantClear"); - pContext->win32.StringFromGUID2 = (ma_proc)ma_dlsym(pContext->win32.hOle32DLL, "StringFromGUID2"); + pContext->win32.CoInitializeEx = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoInitializeEx"); + pContext->win32.CoUninitialize = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoUninitialize"); + pContext->win32.CoCreateInstance = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoCreateInstance"); + pContext->win32.CoTaskMemFree = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "CoTaskMemFree"); + pContext->win32.PropVariantClear = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "PropVariantClear"); + pContext->win32.StringFromGUID2 = (ma_proc)ma_dlsym(pContext, pContext->win32.hOle32DLL, "StringFromGUID2"); /* User32.dll */ - pContext->win32.hUser32DLL = ma_dlopen("user32.dll"); + pContext->win32.hUser32DLL = ma_dlopen(pContext, "user32.dll"); if (pContext->win32.hUser32DLL == NULL) { return MA_FAILED_TO_INIT_BACKEND; } - pContext->win32.GetForegroundWindow = (ma_proc)ma_dlsym(pContext->win32.hUser32DLL, "GetForegroundWindow"); - pContext->win32.GetDesktopWindow = (ma_proc)ma_dlsym(pContext->win32.hUser32DLL, "GetDesktopWindow"); + pContext->win32.GetForegroundWindow = (ma_proc)ma_dlsym(pContext, pContext->win32.hUser32DLL, "GetForegroundWindow"); + pContext->win32.GetDesktopWindow = (ma_proc)ma_dlsym(pContext, pContext->win32.hUser32DLL, "GetDesktopWindow"); /* Advapi32.dll */ - pContext->win32.hAdvapi32DLL = ma_dlopen("advapi32.dll"); + pContext->win32.hAdvapi32DLL = ma_dlopen(pContext, "advapi32.dll"); if (pContext->win32.hAdvapi32DLL == NULL) { return MA_FAILED_TO_INIT_BACKEND; } - pContext->win32.RegOpenKeyExA = (ma_proc)ma_dlsym(pContext->win32.hAdvapi32DLL, "RegOpenKeyExA"); - pContext->win32.RegCloseKey = (ma_proc)ma_dlsym(pContext->win32.hAdvapi32DLL, "RegCloseKey"); - pContext->win32.RegQueryValueExA = (ma_proc)ma_dlsym(pContext->win32.hAdvapi32DLL, "RegQueryValueExA"); + pContext->win32.RegOpenKeyExA = (ma_proc)ma_dlsym(pContext, pContext->win32.hAdvapi32DLL, "RegOpenKeyExA"); + pContext->win32.RegCloseKey = (ma_proc)ma_dlsym(pContext, pContext->win32.hAdvapi32DLL, "RegCloseKey"); + pContext->win32.RegQueryValueExA = (ma_proc)ma_dlsym(pContext, pContext->win32.hAdvapi32DLL, "RegQueryValueExA"); #endif ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE); @@ -23646,7 +23808,7 @@ ma_result ma_context_init_backend_apis__win32(ma_context* pContext) ma_result ma_context_uninit_backend_apis__nix(ma_context* pContext) { #if defined(MA_USE_RUNTIME_LINKING_FOR_PTHREAD) && !defined(MA_NO_RUNTIME_LINKING) - ma_dlclose(pContext->posix.pthreadSO); + ma_dlclose(pContext, pContext->posix.pthreadSO); #else (void)pContext; #endif @@ -23666,7 +23828,7 @@ ma_result ma_context_init_backend_apis__nix(ma_context* pContext) size_t i; for (i = 0; i < sizeof(libpthreadFileNames) / sizeof(libpthreadFileNames[0]); ++i) { - pContext->posix.pthreadSO = ma_dlopen(libpthreadFileNames[i]); + pContext->posix.pthreadSO = ma_dlopen(pContext, libpthreadFileNames[i]); if (pContext->posix.pthreadSO != NULL) { break; } @@ -23676,21 +23838,21 @@ ma_result ma_context_init_backend_apis__nix(ma_context* pContext) return MA_FAILED_TO_INIT_BACKEND; } - pContext->posix.pthread_create = (ma_proc)ma_dlsym(pContext->posix.pthreadSO, "pthread_create"); - pContext->posix.pthread_join = (ma_proc)ma_dlsym(pContext->posix.pthreadSO, "pthread_join"); - pContext->posix.pthread_mutex_init = (ma_proc)ma_dlsym(pContext->posix.pthreadSO, "pthread_mutex_init"); - pContext->posix.pthread_mutex_destroy = (ma_proc)ma_dlsym(pContext->posix.pthreadSO, "pthread_mutex_destroy"); - pContext->posix.pthread_mutex_lock = (ma_proc)ma_dlsym(pContext->posix.pthreadSO, "pthread_mutex_lock"); - pContext->posix.pthread_mutex_unlock = (ma_proc)ma_dlsym(pContext->posix.pthreadSO, "pthread_mutex_unlock"); - pContext->posix.pthread_cond_init = (ma_proc)ma_dlsym(pContext->posix.pthreadSO, "pthread_cond_init"); - pContext->posix.pthread_cond_destroy = (ma_proc)ma_dlsym(pContext->posix.pthreadSO, "pthread_cond_destroy"); - pContext->posix.pthread_cond_wait = (ma_proc)ma_dlsym(pContext->posix.pthreadSO, "pthread_cond_wait"); - pContext->posix.pthread_cond_signal = (ma_proc)ma_dlsym(pContext->posix.pthreadSO, "pthread_cond_signal"); - pContext->posix.pthread_attr_init = (ma_proc)ma_dlsym(pContext->posix.pthreadSO, "pthread_attr_init"); - pContext->posix.pthread_attr_destroy = (ma_proc)ma_dlsym(pContext->posix.pthreadSO, "pthread_attr_destroy"); - pContext->posix.pthread_attr_setschedpolicy = (ma_proc)ma_dlsym(pContext->posix.pthreadSO, "pthread_attr_setschedpolicy"); - pContext->posix.pthread_attr_getschedparam = (ma_proc)ma_dlsym(pContext->posix.pthreadSO, "pthread_attr_getschedparam"); - pContext->posix.pthread_attr_setschedparam = (ma_proc)ma_dlsym(pContext->posix.pthreadSO, "pthread_attr_setschedparam"); + pContext->posix.pthread_create = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_create"); + pContext->posix.pthread_join = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_join"); + pContext->posix.pthread_mutex_init = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_init"); + pContext->posix.pthread_mutex_destroy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_destroy"); + pContext->posix.pthread_mutex_lock = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_lock"); + pContext->posix.pthread_mutex_unlock = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_mutex_unlock"); + pContext->posix.pthread_cond_init = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_init"); + pContext->posix.pthread_cond_destroy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_destroy"); + pContext->posix.pthread_cond_wait = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_wait"); + pContext->posix.pthread_cond_signal = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_cond_signal"); + pContext->posix.pthread_attr_init = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_init"); + pContext->posix.pthread_attr_destroy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_destroy"); + pContext->posix.pthread_attr_setschedpolicy = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_setschedpolicy"); + pContext->posix.pthread_attr_getschedparam = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_getschedparam"); + pContext->posix.pthread_attr_setschedparam = (ma_proc)ma_dlsym(pContext, pContext->posix.pthreadSO, "pthread_attr_setschedparam"); #else pContext->posix.pthread_create = (ma_proc)pthread_create; pContext->posix.pthread_join = (ma_proc)pthread_join; @@ -24431,13 +24593,8 @@ ma_result ma_device_start(ma_device* pDevice) return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_start() called for an uninitialized device.", MA_DEVICE_NOT_INITIALIZED); } - /* - Starting the device doesn't do anything in synchronous mode because in that case it's started automatically with - ma_device_write() and ma_device_read(). It's best to return an error so that the application can be aware that - it's not doing it right. - */ - if (!ma_device__is_async(pDevice)) { - return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_start() called in synchronous mode. This should only be used in asynchronous/callback mode.", MA_DEVICE_NOT_INITIALIZED); + if (ma_device__get_state(pDevice) == MA_STATE_STARTED) { + return ma_post_error(pDevice, MA_LOG_LEVEL_WARNING, "ma_device_start() called when the device is already started.", MA_INVALID_OPERATION); /* Already started. Returning an error to let the application know because it probably means they're doing something wrong. */ } result = MA_ERROR; @@ -24486,14 +24643,8 @@ ma_result ma_device_stop(ma_device* pDevice) return ma_post_error(pDevice, MA_LOG_LEVEL_ERROR, "ma_device_stop() called for an uninitialized device.", MA_DEVICE_NOT_INITIALIZED); } - /* - Stopping is slightly different for synchronous mode. In this case it just tells the driver to stop the internal processing of the device. Also, - stopping in synchronous mode does not require state checking. - */ - if (!ma_device__is_async(pDevice)) { - if (pDevice->pContext->onDeviceStop) { - return pDevice->pContext->onDeviceStop(pDevice); - } + if (ma_device__get_state(pDevice) == MA_STATE_STOPPED) { + return ma_post_error(pDevice, MA_LOG_LEVEL_WARNING, "ma_device_stop() called when the device is already stopped.", MA_INVALID_OPERATION); /* Already stopped. Returning an error to let the application know because it probably means they're doing something wrong. */ } result = MA_ERROR; @@ -29347,8 +29498,8 @@ static MA_INLINE float32x4_t ma_src_sinc__interpolation_factor__neon(const ma_sr { float32x4_t xabs; int32x4_t ixabs; - float32x4_t a; - float32x4_t r; + float32x4_t a + float32x4_t r int* ixabsv; float lo[4]; float hi[4]; @@ -30470,7 +30621,7 @@ ma_uint64 ma_convert_frames_ex(void* pOut, ma_format formatOut, ma_uint32 channe */ totalFramesRead = ma_pcm_converter_read(&converter, pOut, frameCountOut); if (totalFramesRead < frameCountOut) { - ma_uint32 bpf = ma_get_bytes_per_frame(formatIn, channelsIn); + ma_uint32 bpfOut = ma_get_bytes_per_frame(formatOut, channelsOut); data.isFeedingZeros = MA_TRUE; data.totalFrameCount = ((ma_uint64)0xFFFFFFFF << 32) | 0xFFFFFFFF; /* C89 does not support 64-bit constants so need to instead construct it like this. Annoying... */ /*data.totalFrameCount = 0xFFFFFFFFFFFFFFFF;*/ @@ -30483,7 +30634,7 @@ ma_uint64 ma_convert_frames_ex(void* pOut, ma_format formatOut, ma_uint32 channe framesToRead = (frameCountOut - totalFramesRead); ma_assert(framesToRead > 0); - framesJustRead = ma_pcm_converter_read(&converter, ma_offset_ptr(pOut, totalFramesRead * bpf), framesToRead); + framesJustRead = ma_pcm_converter_read(&converter, ma_offset_ptr(pOut, totalFramesRead * bpfOut), framesToRead); totalFramesRead += framesJustRead; if (framesJustRead < framesToRead) { @@ -30493,7 +30644,7 @@ ma_uint64 ma_convert_frames_ex(void* pOut, ma_format formatOut, ma_uint32 channe /* At this point we should have output every sample, but just to be super duper sure, just fill the rest with zeros. */ if (totalFramesRead < frameCountOut) { - ma_zero_memory_64(ma_offset_ptr(pOut, totalFramesRead * bpf), ((frameCountOut - totalFramesRead) * bpf)); + ma_zero_memory_64(ma_offset_ptr(pOut, totalFramesRead * bpfOut), ((frameCountOut - totalFramesRead) * bpfOut)); totalFramesRead = frameCountOut; } } @@ -31395,6 +31546,11 @@ ma_result ma_decoder_internal_on_uninit__wav(ma_decoder* pDecoder) return MA_SUCCESS; } +ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__wav(ma_decoder* pDecoder) +{ + return ((drwav*)pDecoder->pInternalDecoder)->totalPCMFrameCount; +} + ma_result ma_decoder_init_wav__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder) { drwav* pWav; @@ -31412,6 +31568,7 @@ ma_result ma_decoder_init_wav__internal(const ma_decoder_config* pConfig, ma_dec /* If we get here it means we successfully initialized the WAV decoder. We can now initialize the rest of the ma_decoder. */ pDecoder->onSeekToPCMFrame = ma_decoder_internal_on_seek_to_pcm_frame__wav; pDecoder->onUninit = ma_decoder_internal_on_uninit__wav; + pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__wav; pDecoder->pInternalDecoder = pWav; /* Try to be as optimal as possible for the internal format. If miniaudio does not support a format we will fall back to f32. */ @@ -31529,6 +31686,11 @@ ma_result ma_decoder_internal_on_uninit__flac(ma_decoder* pDecoder) return MA_SUCCESS; } +ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__flac(ma_decoder* pDecoder) +{ + return ((drflac*)pDecoder->pInternalDecoder)->totalPCMFrameCount; +} + ma_result ma_decoder_init_flac__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder) { drflac* pFlac; @@ -31546,6 +31708,7 @@ ma_result ma_decoder_init_flac__internal(const ma_decoder_config* pConfig, ma_de /* If we get here it means we successfully initialized the FLAC decoder. We can now initialize the rest of the ma_decoder. */ pDecoder->onSeekToPCMFrame = ma_decoder_internal_on_seek_to_pcm_frame__flac; pDecoder->onUninit = ma_decoder_internal_on_uninit__flac; + pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__flac; pDecoder->pInternalDecoder = pFlac; /* @@ -31754,6 +31917,13 @@ ma_uint32 ma_decoder_internal_on_read_pcm_frames__vorbis(ma_pcm_converter* pDSP, return ma_vorbis_decoder_read_pcm_frames(pVorbis, pDecoder, pSamplesOut, frameCount); } +ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__vorbis(ma_decoder* pDecoder) +{ + /* No good way to do this with Vorbis. */ + (void)pDecoder; + return 0; +} + ma_result ma_decoder_init_vorbis__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder) { ma_result result; @@ -31847,6 +32017,7 @@ ma_result ma_decoder_init_vorbis__internal(const ma_decoder_config* pConfig, ma_ pDecoder->onSeekToPCMFrame = ma_decoder_internal_on_seek_to_pcm_frame__vorbis; pDecoder->onUninit = ma_decoder_internal_on_uninit__vorbis; + pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__vorbis; pDecoder->pInternalDecoder = pVorbis; /* The internal format is always f32. */ @@ -31927,6 +32098,11 @@ ma_result ma_decoder_internal_on_uninit__mp3(ma_decoder* pDecoder) return MA_SUCCESS; } +ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__mp3(ma_decoder* pDecoder) +{ + return drmp3_get_pcm_frame_count((drmp3*)pDecoder->pInternalDecoder); +} + ma_result ma_decoder_init_mp3__internal(const ma_decoder_config* pConfig, ma_decoder* pDecoder) { drmp3* pMP3; @@ -31962,6 +32138,7 @@ ma_result ma_decoder_init_mp3__internal(const ma_decoder_config* pConfig, ma_dec /* If we get here it means we successfully initialized the MP3 decoder. We can now initialize the rest of the ma_decoder. */ pDecoder->onSeekToPCMFrame = ma_decoder_internal_on_seek_to_pcm_frame__mp3; pDecoder->onUninit = ma_decoder_internal_on_uninit__mp3; + pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__mp3; pDecoder->pInternalDecoder = pMP3; /* Internal format. */ @@ -32047,6 +32224,12 @@ ma_result ma_decoder_internal_on_uninit__raw(ma_decoder* pDecoder) return MA_SUCCESS; } +ma_uint64 ma_decoder_internal_on_get_length_in_pcm_frames__raw(ma_decoder* pDecoder) +{ + (void)pDecoder; + return 0; +} + ma_result ma_decoder_init_raw__internal(const ma_decoder_config* pConfigIn, const ma_decoder_config* pConfigOut, ma_decoder* pDecoder) { ma_result result; @@ -32057,6 +32240,7 @@ ma_result ma_decoder_init_raw__internal(const ma_decoder_config* pConfigIn, cons pDecoder->onSeekToPCMFrame = ma_decoder_internal_on_seek_to_pcm_frame__raw; pDecoder->onUninit = ma_decoder_internal_on_uninit__raw; + pDecoder->onGetLengthInPCMFrames = ma_decoder_internal_on_get_length_in_pcm_frames__raw; /* Internal format. */ pDecoder->internalFormat = pConfigIn->format; @@ -32431,6 +32615,7 @@ ma_result ma_decoder_init_memory_raw(const void* pData, size_t dataSize, const m #include #if !defined(_MSC_VER) && !defined(__DMC__) #include /* For strcasecmp(). */ +#include /* For wcsrtombs() */ #endif const char* ma_path_file_name(const char* path) @@ -32460,6 +32645,34 @@ const char* ma_path_file_name(const char* path) return fileName; } +const wchar_t* ma_path_file_name_w(const wchar_t* path) +{ + const wchar_t* fileName; + + if (path == NULL) { + return NULL; + } + + fileName = path; + + /* We just loop through the path until we find the last slash. */ + while (path[0] != '\0') { + if (path[0] == '/' || path[0] == '\\') { + fileName = path; + } + + path += 1; + } + + /* At this point the file name is sitting on a slash, so just move forward. */ + while (fileName[0] != '\0' && (fileName[0] == '/' || fileName[0] == '\\')) { + fileName += 1; + } + + return fileName; +} + + const char* ma_path_extension(const char* path) { const char* extension; @@ -32485,6 +32698,32 @@ const char* ma_path_extension(const char* path) return (lastOccurance != NULL) ? lastOccurance : extension; } +const wchar_t* ma_path_extension_w(const wchar_t* path) +{ + const wchar_t* extension; + const wchar_t* lastOccurance; + + if (path == NULL) { + path = L""; + } + + extension = ma_path_file_name_w(path); + lastOccurance = NULL; + + /* Just find the last '.' and return. */ + while (extension[0] != '\0') { + if (extension[0] == '.') { + extension += 1; + lastOccurance = extension; + } + + extension += 1; + } + + return (lastOccurance != NULL) ? lastOccurance : extension; +} + + ma_bool32 ma_path_extension_equal(const char* path, const char* extension) { const char* ext1; @@ -32504,6 +32743,49 @@ ma_bool32 ma_path_extension_equal(const char* path, const char* extension) #endif } +ma_bool32 ma_path_extension_equal_w(const wchar_t* path, const wchar_t* extension) +{ + const wchar_t* ext1; + const wchar_t* ext2; + + if (path == NULL || extension == NULL) { + return MA_FALSE; + } + + ext1 = extension; + ext2 = ma_path_extension_w(path); + +#if defined(_MSC_VER) || defined(__DMC__) + return _wcsicmp(ext1, ext2) == 0; +#else + /* + I'm not aware of a wide character version of strcasecmp(). I'm therefore converting the extensions to multibyte strings and comparing those. This + isn't the most efficient way to do it, but it should work OK. + */ + { + char ext1MB[4096]; + char ext2MB[4096]; + const wchar_t* pext1 = ext1; + const wchar_t* pext2 = ext2; + mbstate_t mbs1; + mbstate_t mbs2; + + ma_zero_object(&mbs1); + ma_zero_object(&mbs2); + + if (wcsrtombs(ext1MB, &pext1, sizeof(ext1MB), &mbs1) == (size_t)-1) { + return MA_FALSE; + } + if (wcsrtombs(ext2MB, &pext2, sizeof(ext2MB), &mbs2) == (size_t)-1) { + return MA_FALSE; + } + + return strcasecmp(ext1MB, ext2MB) == 0; + } +#endif +} + + size_t ma_decoder__on_read_stdio(ma_decoder* pDecoder, void* pBufferOut, size_t bytesToRead) { return fread(pBufferOut, 1, bytesToRead, (FILE*)pDecoder->pUserData); @@ -32546,6 +32828,77 @@ ma_result ma_decoder__preinit_file(const char* pFilePath, const ma_decoder_confi return MA_SUCCESS; } +ma_result ma_decoder__preinit_file_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ + FILE* pFile; + + if (pDecoder == NULL) { + return MA_INVALID_ARGS; + } + + ma_zero_object(pDecoder); + + if (pFilePath == NULL || pFilePath[0] == '\0') { + return MA_INVALID_ARGS; + } + +#if defined(_WIN32) + /* Use _wfopen() on Windows. */ + #if defined(_MSC_VER) && _MSC_VER >= 1400 + if (_wfopen_s(&pFile, pFilePath, L"rb") != 0) { + return MA_ERROR; + } + #else + pFile = _wfopen(pFilePath, L"rb"); + if (pFile == NULL) { + return MA_ERROR; + } + #endif +#else + /* + Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can + think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for + maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility. + */ + { + mbstate_t mbs; + size_t lenMB; + const wchar_t* pFilePathTemp = pFilePath; + char* pFilePathMB = NULL; + + /* Get the length first. */ + ma_zero_object(&mbs); + lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs); + if (lenMB == (size_t)-1) { + return MA_ERROR; + } + + pFilePathMB = (char*)MA_MALLOC(lenMB + 1); + if (pFilePathMB == NULL) { + return MA_OUT_OF_MEMORY; + } + + pFilePathTemp = pFilePath; + ma_zero_object(&mbs); + wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs); + + pFile = fopen(pFilePathMB, "rb"); + + MA_FREE(pFilePathMB); + } + + if (pFile == NULL) { + return MA_ERROR; + } +#endif + + /* We need to manually set the user data so the calls to ma_decoder__on_seek_stdio() succeed. */ + pDecoder->pUserData = pFile; + + (void)pConfig; + return MA_SUCCESS; +} + ma_result ma_decoder_init_file(const char* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) { ma_result result = ma_decoder__preinit_file(pFilePath, pConfig, pDecoder); /* This sets pDecoder->pUserData to a FILE*. */ @@ -32626,6 +32979,88 @@ ma_result ma_decoder_init_file_mp3(const char* pFilePath, const ma_decoder_confi return ma_decoder_init_mp3(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder); } + + +ma_result ma_decoder_init_file_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ + ma_result result = ma_decoder__preinit_file_w(pFilePath, pConfig, pDecoder); /* This sets pDecoder->pUserData to a FILE*. */ + if (result != MA_SUCCESS) { + return result; + } + + /* WAV */ + if (ma_path_extension_equal_w(pFilePath, L"wav")) { + result = ma_decoder_init_wav(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder); + if (result == MA_SUCCESS) { + return MA_SUCCESS; + } + + ma_decoder__on_seek_stdio(pDecoder, 0, ma_seek_origin_start); + } + + /* FLAC */ + if (ma_path_extension_equal_w(pFilePath, L"flac")) { + result = ma_decoder_init_flac(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder); + if (result == MA_SUCCESS) { + return MA_SUCCESS; + } + + ma_decoder__on_seek_stdio(pDecoder, 0, ma_seek_origin_start); + } + + /* MP3 */ + if (ma_path_extension_equal_w(pFilePath, L"mp3")) { + result = ma_decoder_init_mp3(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder); + if (result == MA_SUCCESS) { + return MA_SUCCESS; + } + + ma_decoder__on_seek_stdio(pDecoder, 0, ma_seek_origin_start); + } + + /* Trial and error. */ + return ma_decoder_init(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder); +} + +ma_result ma_decoder_init_file_wav_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ + ma_result result = ma_decoder__preinit_file_w(pFilePath, pConfig, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + return ma_decoder_init_wav(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder); +} + +ma_result ma_decoder_init_file_flac_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ + ma_result result = ma_decoder__preinit_file_w(pFilePath, pConfig, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + return ma_decoder_init_flac(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder); +} + +ma_result ma_decoder_init_file_vorbis_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ + ma_result result = ma_decoder__preinit_file_w(pFilePath, pConfig, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + return ma_decoder_init_vorbis(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder); +} + +ma_result ma_decoder_init_file_mp3_w(const wchar_t* pFilePath, const ma_decoder_config* pConfig, ma_decoder* pDecoder) +{ + ma_result result = ma_decoder__preinit_file_w(pFilePath, pConfig, pDecoder); + if (result != MA_SUCCESS) { + return result; + } + + return ma_decoder_init_mp3(ma_decoder__on_read_stdio, ma_decoder__on_seek_stdio, pDecoder->pUserData, pConfig, pDecoder); +} #endif ma_result ma_decoder_uninit(ma_decoder* pDecoder) @@ -32648,6 +33083,19 @@ ma_result ma_decoder_uninit(ma_decoder* pDecoder) return MA_SUCCESS; } +ma_uint64 ma_decoder_get_length_in_pcm_frames(ma_decoder* pDecoder) +{ + if (pDecoder == NULL) { + return 0; + } + + if (pDecoder->onGetLengthInPCMFrames) { + return pDecoder->onGetLengthInPCMFrames(pDecoder); + } + + return 0; +} + ma_uint64 ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount) { if (pDecoder == NULL) { @@ -32913,6 +33361,21 @@ Device /* REVISION HISTORY ================ +v0.9.6 - 2019-xx-xx + - Add support for loading decoders using a wchar_t string for file paths. + - Don't trigger an assert when ma_device_start() is called on a device that is already started. This will now log a warning + and return MA_INVALID_OPERATION. The same applies for ma_device_stop(). + - Try fixing an issue with PulseAudio taking a long time to start playback. + - Fix a bug in ma_convert_frames() and ma_convert_frames_ex(). + - Fix memory leaks in the WASAPI backend. + - Fix a compilation error with Visual Studio 2010. + +v0.9.5 - 2019-05-21 + - Add logging to ma_dlopen() and ma_dlsym(). + - Add ma_decoder_get_length_in_pcm_frames(). + - Fix a bug with capture on the OpenSL|ES backend. + - Fix a bug with the ALSA backend where a device would not restart after being stopped. + v0.9.4 - 2019-05-06 - Add support for C89. With this change, miniaudio should compile clean with GCC/Clang with "-std=c89 -ansi -pedantic" and Microsoft compilers back to VC6. Other compilers should also work, but have not been tested. diff --git a/src/external/stb_image_write.h b/src/external/stb_image_write.h index a19b548ae..082eb69d5 100644 --- a/src/external/stb_image_write.h +++ b/src/external/stb_image_write.h @@ -10,11 +10,6 @@ Will probably not work correctly with strict-aliasing optimizations. - If using a modern Microsoft Compiler, non-safe versions of CRT calls may cause - compilation warnings or even errors. To avoid this, also before #including, - - #define STBI_MSC_SECURE_CRT - ABOUT: This header file is a library for writing images to C stdio or a callback.