minesweeper

A minewseeper implementation to play around with Hare and Raylib
git clone https://git.tronto.net/minesweeper
Download | Log | Files | Refs | README | LICENSE

raudio.c (109654B)


      1 /**********************************************************************************************
      2 *
      3 *   raudio v1.1 - A simple and easy-to-use audio library based on miniaudio
      4 *
      5 *   FEATURES:
      6 *       - Manage audio device (init/close)
      7 *       - Manage raw audio context
      8 *       - Manage mixing channels
      9 *       - Load and unload audio files
     10 *       - Format wave data (sample rate, size, channels)
     11 *       - Play/Stop/Pause/Resume loaded audio
     12 *
     13 *   CONFIGURATION:
     14 *       #define SUPPORT_MODULE_RAUDIO
     15 *           raudio module is included in the build
     16 *
     17 *       #define RAUDIO_STANDALONE
     18 *           Define to use the module as standalone library (independently of raylib).
     19 *           Required types and functions are defined in the same module.
     20 *
     21 *       #define SUPPORT_FILEFORMAT_WAV
     22 *       #define SUPPORT_FILEFORMAT_OGG
     23 *       #define SUPPORT_FILEFORMAT_MP3
     24 *       #define SUPPORT_FILEFORMAT_QOA
     25 *       #define SUPPORT_FILEFORMAT_FLAC
     26 *       #define SUPPORT_FILEFORMAT_XM
     27 *       #define SUPPORT_FILEFORMAT_MOD
     28 *           Selected desired fileformats to be supported for loading. Some of those formats are
     29 *           supported by default, to remove support, just comment unrequired #define in this module
     30 *
     31 *   DEPENDENCIES:
     32 *       miniaudio.h  - Audio device management lib (https://github.com/mackron/miniaudio)
     33 *       stb_vorbis.h - Ogg audio files loading (http://www.nothings.org/stb_vorbis/)
     34 *       dr_wav.h     - WAV audio files loading (http://github.com/mackron/dr_libs)
     35 *       dr_mp3.h     - MP3 audio file loading (https://github.com/mackron/dr_libs)
     36 *       dr_flac.h    - FLAC audio file loading (https://github.com/mackron/dr_libs)
     37 *       jar_xm.h     - XM module file loading
     38 *       jar_mod.h    - MOD audio file loading
     39 *
     40 *   CONTRIBUTORS:
     41 *       David Reid (github: @mackron) (Nov. 2017):
     42 *           - Complete port to miniaudio library
     43 *
     44 *       Joshua Reisenauer (github: @kd7tck) (2015):
     45 *           - XM audio module support (jar_xm)
     46 *           - MOD audio module support (jar_mod)
     47 *           - Mixing channels support
     48 *           - Raw audio context support
     49 *
     50 *
     51 *   LICENSE: zlib/libpng
     52 *
     53 *   Copyright (c) 2013-2024 Ramon Santamaria (@raysan5)
     54 *
     55 *   This software is provided "as-is", without any express or implied warranty. In no event
     56 *   will the authors be held liable for any damages arising from the use of this software.
     57 *
     58 *   Permission is granted to anyone to use this software for any purpose, including commercial
     59 *   applications, and to alter it and redistribute it freely, subject to the following restrictions:
     60 *
     61 *     1. The origin of this software must not be misrepresented; you must not claim that you
     62 *     wrote the original software. If you use this software in a product, an acknowledgment
     63 *     in the product documentation would be appreciated but is not required.
     64 *
     65 *     2. Altered source versions must be plainly marked as such, and must not be misrepresented
     66 *     as being the original software.
     67 *
     68 *     3. This notice may not be removed or altered from any source distribution.
     69 *
     70 **********************************************************************************************/
     71 
     72 #if defined(RAUDIO_STANDALONE)
     73     #include "raudio.h"
     74 #else
     75     #include "raylib.h"         // Declares module functions
     76 
     77     // Check if config flags have been externally provided on compilation line
     78     #if !defined(EXTERNAL_CONFIG_FLAGS)
     79         #include "config.h"     // Defines module configuration flags
     80     #endif
     81     #include "utils.h"          // Required for: fopen() Android mapping
     82 #endif
     83 
     84 #if defined(SUPPORT_MODULE_RAUDIO)
     85 
     86 #if defined(_WIN32)
     87 // To avoid conflicting windows.h symbols with raylib, some flags are defined
     88 // WARNING: Those flags avoid inclusion of some Win32 headers that could be required
     89 // by user at some point and won't be included...
     90 //-------------------------------------------------------------------------------------
     91 
     92 // If defined, the following flags inhibit definition of the indicated items.
     93 #define NOGDICAPMASKS     // CC_*, LC_*, PC_*, CP_*, TC_*, RC_
     94 #define NOVIRTUALKEYCODES // VK_*
     95 #define NOWINMESSAGES     // WM_*, EM_*, LB_*, CB_*
     96 #define NOWINSTYLES       // WS_*, CS_*, ES_*, LBS_*, SBS_*, CBS_*
     97 #define NOSYSMETRICS      // SM_*
     98 #define NOMENUS           // MF_*
     99 #define NOICONS           // IDI_*
    100 #define NOKEYSTATES       // MK_*
    101 #define NOSYSCOMMANDS     // SC_*
    102 #define NORASTEROPS       // Binary and Tertiary raster ops
    103 #define NOSHOWWINDOW      // SW_*
    104 #define OEMRESOURCE       // OEM Resource values
    105 #define NOATOM            // Atom Manager routines
    106 #define NOCLIPBOARD       // Clipboard routines
    107 #define NOCOLOR           // Screen colors
    108 #define NOCTLMGR          // Control and Dialog routines
    109 #define NODRAWTEXT        // DrawText() and DT_*
    110 #define NOGDI             // All GDI defines and routines
    111 #define NOKERNEL          // All KERNEL defines and routines
    112 #define NOUSER            // All USER defines and routines
    113 //#define NONLS             // All NLS defines and routines
    114 #define NOMB              // MB_* and MessageBox()
    115 #define NOMEMMGR          // GMEM_*, LMEM_*, GHND, LHND, associated routines
    116 #define NOMETAFILE        // typedef METAFILEPICT
    117 #define NOMINMAX          // Macros min(a,b) and max(a,b)
    118 #define NOMSG             // typedef MSG and associated routines
    119 #define NOOPENFILE        // OpenFile(), OemToAnsi, AnsiToOem, and OF_*
    120 #define NOSCROLL          // SB_* and scrolling routines
    121 #define NOSERVICE         // All Service Controller routines, SERVICE_ equates, etc.
    122 #define NOSOUND           // Sound driver routines
    123 #define NOTEXTMETRIC      // typedef TEXTMETRIC and associated routines
    124 #define NOWH              // SetWindowsHook and WH_*
    125 #define NOWINOFFSETS      // GWL_*, GCL_*, associated routines
    126 #define NOCOMM            // COMM driver routines
    127 #define NOKANJI           // Kanji support stuff.
    128 #define NOHELP            // Help engine interface.
    129 #define NOPROFILER        // Profiler interface.
    130 #define NODEFERWINDOWPOS  // DeferWindowPos routines
    131 #define NOMCX             // Modem Configuration Extensions
    132 
    133 // Type required before windows.h inclusion
    134 typedef struct tagMSG *LPMSG;
    135 
    136 #include <windows.h>        // Windows functionality (miniaudio)
    137 
    138 // Type required by some unused function...
    139 typedef struct tagBITMAPINFOHEADER {
    140   DWORD biSize;
    141   LONG  biWidth;
    142   LONG  biHeight;
    143   WORD  biPlanes;
    144   WORD  biBitCount;
    145   DWORD biCompression;
    146   DWORD biSizeImage;
    147   LONG  biXPelsPerMeter;
    148   LONG  biYPelsPerMeter;
    149   DWORD biClrUsed;
    150   DWORD biClrImportant;
    151 } BITMAPINFOHEADER, *PBITMAPINFOHEADER;
    152 
    153 #include <objbase.h>        // Component Object Model (COM) header
    154 #include <mmreg.h>          // Windows Multimedia, defines some WAVE structs
    155 #include <mmsystem.h>       // Windows Multimedia, used by Windows GDI, defines DIBINDEX macro
    156 
    157 // Some required types defined for MSVC/TinyC compiler
    158 #if defined(_MSC_VER) || defined(__TINYC__)
    159     #include "propidl.h"
    160 #endif
    161 #endif
    162 
    163 #define MA_MALLOC RL_MALLOC
    164 #define MA_FREE RL_FREE
    165 
    166 #define MA_NO_JACK
    167 #define MA_NO_WAV
    168 #define MA_NO_FLAC
    169 #define MA_NO_MP3
    170 #define MA_NO_RESOURCE_MANAGER
    171 #define MA_NO_NODE_GRAPH
    172 #define MA_NO_ENGINE
    173 #define MA_NO_GENERATION
    174 
    175 // Threading model: Default: [0] COINIT_MULTITHREADED: COM calls objects on any thread (free threading)
    176 #define MA_COINIT_VALUE  2              // [2] COINIT_APARTMENTTHREADED: Each object has its own thread (apartment model)
    177 
    178 #define MINIAUDIO_IMPLEMENTATION
    179 //#define MA_DEBUG_OUTPUT
    180 #include "external/miniaudio.h"         // Audio device initialization and management
    181 #undef PlaySound                        // Win32 API: windows.h > mmsystem.h defines PlaySound macro
    182 
    183 #include <stdlib.h>                     // Required for: malloc(), free()
    184 #include <stdio.h>                      // Required for: FILE, fopen(), fclose(), fread()
    185 #include <string.h>                     // Required for: strcmp() [Used in IsFileExtension(), LoadWaveFromMemory(), LoadMusicStreamFromMemory()]
    186 
    187 #if defined(RAUDIO_STANDALONE)
    188     #ifndef TRACELOG
    189         #define TRACELOG(level, ...)    printf(__VA_ARGS__)
    190     #endif
    191 
    192     // Allow custom memory allocators
    193     #ifndef RL_MALLOC
    194         #define RL_MALLOC(sz)           malloc(sz)
    195     #endif
    196     #ifndef RL_CALLOC
    197         #define RL_CALLOC(n,sz)         calloc(n,sz)
    198     #endif
    199     #ifndef RL_REALLOC
    200         #define RL_REALLOC(ptr,sz)      realloc(ptr,sz)
    201     #endif
    202     #ifndef RL_FREE
    203         #define RL_FREE(ptr)            free(ptr)
    204     #endif
    205 #endif
    206 
    207 #if defined(SUPPORT_FILEFORMAT_WAV)
    208     #define DRWAV_MALLOC RL_MALLOC
    209     #define DRWAV_REALLOC RL_REALLOC
    210     #define DRWAV_FREE RL_FREE
    211 
    212     #define DR_WAV_IMPLEMENTATION
    213     #include "external/dr_wav.h"        // WAV loading functions
    214 #endif
    215 
    216 #if defined(SUPPORT_FILEFORMAT_OGG)
    217     // TODO: Remap stb_vorbis malloc()/free() calls to RL_MALLOC/RL_FREE
    218     #include "external/stb_vorbis.c"    // OGG loading functions
    219 #endif
    220 
    221 #if defined(SUPPORT_FILEFORMAT_MP3)
    222     #define DRMP3_MALLOC RL_MALLOC
    223     #define DRMP3_REALLOC RL_REALLOC
    224     #define DRMP3_FREE RL_FREE
    225 
    226     #define DR_MP3_IMPLEMENTATION
    227     #include "external/dr_mp3.h"        // MP3 loading functions
    228 #endif
    229 
    230 #if defined(SUPPORT_FILEFORMAT_QOA)
    231     #define QOA_MALLOC RL_MALLOC
    232     #define QOA_FREE RL_FREE
    233 
    234     #if defined(_MSC_VER)           // Disable some MSVC warning
    235         #pragma warning(push)
    236         #pragma warning(disable : 4018)
    237         #pragma warning(disable : 4267)
    238         #pragma warning(disable : 4244)
    239     #endif
    240 
    241     #define QOA_IMPLEMENTATION
    242     #include "external/qoa.h"           // QOA loading and saving functions
    243     #include "external/qoaplay.c"       // QOA stream playing helper functions
    244 
    245     #if defined(_MSC_VER)
    246         #pragma warning(pop)        // Disable MSVC warning suppression
    247     #endif
    248 #endif
    249 
    250 #if defined(SUPPORT_FILEFORMAT_FLAC)
    251     #define DRFLAC_MALLOC RL_MALLOC
    252     #define DRFLAC_REALLOC RL_REALLOC
    253     #define DRFLAC_FREE RL_FREE
    254 
    255     #define DR_FLAC_IMPLEMENTATION
    256     #define DR_FLAC_NO_WIN32_IO
    257     #include "external/dr_flac.h"       // FLAC loading functions
    258 #endif
    259 
    260 #if defined(SUPPORT_FILEFORMAT_XM)
    261     #define JARXM_MALLOC RL_MALLOC
    262     #define JARXM_FREE RL_FREE
    263 
    264     #if defined(_MSC_VER)           // Disable some MSVC warning
    265         #pragma warning(push)
    266         #pragma warning(disable : 4244)
    267     #endif
    268 
    269     #define JAR_XM_IMPLEMENTATION
    270     #include "external/jar_xm.h"        // XM loading functions
    271 
    272     #if defined(_MSC_VER)
    273         #pragma warning(pop)        // Disable MSVC warning suppression
    274     #endif
    275 #endif
    276 
    277 #if defined(SUPPORT_FILEFORMAT_MOD)
    278     #define JARMOD_MALLOC RL_MALLOC
    279     #define JARMOD_FREE RL_FREE
    280 
    281     #define JAR_MOD_IMPLEMENTATION
    282     #include "external/jar_mod.h"       // MOD loading functions
    283 #endif
    284 
    285 //----------------------------------------------------------------------------------
    286 // Defines and Macros
    287 //----------------------------------------------------------------------------------
    288 #ifndef AUDIO_DEVICE_FORMAT
    289     #define AUDIO_DEVICE_FORMAT    ma_format_f32    // Device output format (float-32bit)
    290 #endif
    291 #ifndef AUDIO_DEVICE_CHANNELS
    292     #define AUDIO_DEVICE_CHANNELS              2    // Device output channels: stereo
    293 #endif
    294 #ifndef AUDIO_DEVICE_SAMPLE_RATE
    295     #define AUDIO_DEVICE_SAMPLE_RATE           0    // Device output sample rate
    296 #endif
    297 
    298 #ifndef MAX_AUDIO_BUFFER_POOL_CHANNELS
    299     #define MAX_AUDIO_BUFFER_POOL_CHANNELS    16    // Audio pool channels
    300 #endif
    301 
    302 //----------------------------------------------------------------------------------
    303 // Types and Structures Definition
    304 //----------------------------------------------------------------------------------
    305 #if defined(RAUDIO_STANDALONE)
    306 // Trace log level
    307 // NOTE: Organized by priority level
    308 typedef enum {
    309     LOG_ALL = 0,        // Display all logs
    310     LOG_TRACE,          // Trace logging, intended for internal use only
    311     LOG_DEBUG,          // Debug logging, used for internal debugging, it should be disabled on release builds
    312     LOG_INFO,           // Info logging, used for program execution info
    313     LOG_WARNING,        // Warning logging, used on recoverable failures
    314     LOG_ERROR,          // Error logging, used on unrecoverable failures
    315     LOG_FATAL,          // Fatal logging, used to abort program: exit(EXIT_FAILURE)
    316     LOG_NONE            // Disable logging
    317 } TraceLogLevel;
    318 #endif
    319 
    320 // Music context type
    321 // NOTE: Depends on data structure provided by the library
    322 // in charge of reading the different file types
    323 typedef enum {
    324     MUSIC_AUDIO_NONE = 0,   // No audio context loaded
    325     MUSIC_AUDIO_WAV,        // WAV audio context
    326     MUSIC_AUDIO_OGG,        // OGG audio context
    327     MUSIC_AUDIO_FLAC,       // FLAC audio context
    328     MUSIC_AUDIO_MP3,        // MP3 audio context
    329     MUSIC_AUDIO_QOA,        // QOA audio context
    330     MUSIC_MODULE_XM,        // XM module audio context
    331     MUSIC_MODULE_MOD        // MOD module audio context
    332 } MusicContextType;
    333 
    334 // NOTE: Different logic is used when feeding data to the playback device
    335 // depending on whether data is streamed (Music vs Sound)
    336 typedef enum {
    337     AUDIO_BUFFER_USAGE_STATIC = 0,
    338     AUDIO_BUFFER_USAGE_STREAM
    339 } AudioBufferUsage;
    340 
    341 // Audio buffer struct
    342 struct rAudioBuffer {
    343     ma_data_converter converter;    // Audio data converter
    344 
    345     AudioCallback callback;         // Audio buffer callback for buffer filling on audio threads
    346     rAudioProcessor *processor;     // Audio processor
    347 
    348     float volume;                   // Audio buffer volume
    349     float pitch;                    // Audio buffer pitch
    350     float pan;                      // Audio buffer pan (0.0f to 1.0f)
    351 
    352     bool playing;                   // Audio buffer state: AUDIO_PLAYING
    353     bool paused;                    // Audio buffer state: AUDIO_PAUSED
    354     bool looping;                   // Audio buffer looping, default to true for AudioStreams
    355     int usage;                      // Audio buffer usage mode: STATIC or STREAM
    356 
    357     bool isSubBufferProcessed[2];   // SubBuffer processed (virtual double buffer)
    358     unsigned int sizeInFrames;      // Total buffer size in frames
    359     unsigned int frameCursorPos;    // Frame cursor position
    360     unsigned int framesProcessed;   // Total frames processed in this buffer (required for play timing)
    361 
    362     unsigned char *data;            // Data buffer, on music stream keeps filling
    363 
    364     rAudioBuffer *next;             // Next audio buffer on the list
    365     rAudioBuffer *prev;             // Previous audio buffer on the list
    366 };
    367 
    368 // Audio processor struct
    369 // NOTE: Useful to apply effects to an AudioBuffer
    370 struct rAudioProcessor {
    371     AudioCallback process;          // Processor callback function
    372     rAudioProcessor *next;          // Next audio processor on the list
    373     rAudioProcessor *prev;          // Previous audio processor on the list
    374 };
    375 
    376 #define AudioBuffer rAudioBuffer    // HACK: To avoid CoreAudio (macOS) symbol collision
    377 
    378 // Audio data context
    379 typedef struct AudioData {
    380     struct {
    381         ma_context context;         // miniaudio context data
    382         ma_device device;           // miniaudio device
    383         ma_mutex lock;              // miniaudio mutex lock
    384         bool isReady;               // Check if audio device is ready
    385         size_t pcmBufferSize;       // Pre-allocated buffer size
    386         void *pcmBuffer;            // Pre-allocated buffer to read audio data from file/memory
    387     } System;
    388     struct {
    389         AudioBuffer *first;         // Pointer to first AudioBuffer in the list
    390         AudioBuffer *last;          // Pointer to last AudioBuffer in the list
    391         int defaultSize;            // Default audio buffer size for audio streams
    392     } Buffer;
    393     rAudioProcessor *mixedProcessor;
    394 } AudioData;
    395 
    396 //----------------------------------------------------------------------------------
    397 // Global Variables Definition
    398 //----------------------------------------------------------------------------------
    399 static AudioData AUDIO = {          // Global AUDIO context
    400 
    401     // NOTE: Music buffer size is defined by number of samples, independent of sample size and channels number
    402     // After some math, considering a sampleRate of 48000, a buffer refill rate of 1/60 seconds and a
    403     // standard double-buffering system, a 4096 samples buffer has been chosen, it should be enough
    404     // In case of music-stalls, just increase this number
    405     .Buffer.defaultSize = 0,
    406     .mixedProcessor = NULL
    407 };
    408 
    409 //----------------------------------------------------------------------------------
    410 // Module specific Functions Declaration
    411 //----------------------------------------------------------------------------------
    412 static void OnLog(void *pUserData, ma_uint32 level, const char *pMessage);
    413 
    414 // Reads audio data from an AudioBuffer object in internal/device formats
    415 static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer, void *framesOut, ma_uint32 frameCount);
    416 static ma_uint32 ReadAudioBufferFramesInMixingFormat(AudioBuffer *audioBuffer, float *framesOut, ma_uint32 frameCount);
    417 
    418 static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const void *pFramesInput, ma_uint32 frameCount);
    419 static void MixAudioFrames(float *framesOut, const float *framesIn, ma_uint32 frameCount, AudioBuffer *buffer);
    420 
    421 static bool IsAudioBufferPlayingInLockedState(AudioBuffer *buffer);
    422 static void StopAudioBufferInLockedState(AudioBuffer *buffer);
    423 static void UpdateAudioStreamInLockedState(AudioStream stream, const void *data, int frameCount);
    424 
    425 #if defined(RAUDIO_STANDALONE)
    426 static bool IsFileExtension(const char *fileName, const char *ext); // Check file extension
    427 static const char *GetFileExtension(const char *fileName);          // Get pointer to extension for a filename string (includes the dot: .png)
    428 static const char *GetFileName(const char *filePath);               // Get pointer to filename for a path string
    429 static const char *GetFileNameWithoutExt(const char *filePath);     // Get filename string without extension (uses static string)
    430 
    431 static unsigned char *LoadFileData(const char *fileName, int *dataSize);    // Load file data as byte array (read)
    432 static bool SaveFileData(const char *fileName, void *data, int dataSize);   // Save data to file from byte array (write)
    433 static bool SaveFileText(const char *fileName, char *text);         // Save text data to file (write), string must be '\0' terminated
    434 #endif
    435 
    436 //----------------------------------------------------------------------------------
    437 // AudioBuffer management functions declaration
    438 // NOTE: Those functions are not exposed by raylib... for the moment
    439 //----------------------------------------------------------------------------------
    440 AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 sizeInFrames, int usage);
    441 void UnloadAudioBuffer(AudioBuffer *buffer);
    442 
    443 bool IsAudioBufferPlaying(AudioBuffer *buffer);
    444 void PlayAudioBuffer(AudioBuffer *buffer);
    445 void StopAudioBuffer(AudioBuffer *buffer);
    446 void PauseAudioBuffer(AudioBuffer *buffer);
    447 void ResumeAudioBuffer(AudioBuffer *buffer);
    448 void SetAudioBufferVolume(AudioBuffer *buffer, float volume);
    449 void SetAudioBufferPitch(AudioBuffer *buffer, float pitch);
    450 void SetAudioBufferPan(AudioBuffer *buffer, float pan);
    451 void TrackAudioBuffer(AudioBuffer *buffer);
    452 void UntrackAudioBuffer(AudioBuffer *buffer);
    453 
    454 
    455 //----------------------------------------------------------------------------------
    456 // Module Functions Definition - Audio Device initialization and Closing
    457 //----------------------------------------------------------------------------------
    458 // Initialize audio device
    459 void InitAudioDevice(void)
    460 {
    461     // Init audio context
    462     ma_context_config ctxConfig = ma_context_config_init();
    463     ma_log_callback_init(OnLog, NULL);
    464 
    465     ma_result result = ma_context_init(NULL, 0, &ctxConfig, &AUDIO.System.context);
    466     if (result != MA_SUCCESS)
    467     {
    468         TRACELOG(LOG_WARNING, "AUDIO: Failed to initialize context");
    469         return;
    470     }
    471 
    472     // Init audio device
    473     // NOTE: Using the default device. Format is floating point because it simplifies mixing
    474     ma_device_config config = ma_device_config_init(ma_device_type_playback);
    475     config.playback.pDeviceID = NULL;  // NULL for the default playback AUDIO.System.device
    476     config.playback.format = AUDIO_DEVICE_FORMAT;
    477     config.playback.channels = AUDIO_DEVICE_CHANNELS;
    478     config.capture.pDeviceID = NULL;  // NULL for the default capture AUDIO.System.device
    479     config.capture.format = ma_format_s16;
    480     config.capture.channels = 1;
    481     config.sampleRate = AUDIO_DEVICE_SAMPLE_RATE;
    482     config.dataCallback = OnSendAudioDataToDevice;
    483     config.pUserData = NULL;
    484 
    485     result = ma_device_init(&AUDIO.System.context, &config, &AUDIO.System.device);
    486     if (result != MA_SUCCESS)
    487     {
    488         TRACELOG(LOG_WARNING, "AUDIO: Failed to initialize playback device");
    489         ma_context_uninit(&AUDIO.System.context);
    490         return;
    491     }
    492 
    493     // Mixing happens on a separate thread which means we need to synchronize. I'm using a mutex here to make things simple, but may
    494     // want to look at something a bit smarter later on to keep everything real-time, if that's necessary
    495     if (ma_mutex_init(&AUDIO.System.lock) != MA_SUCCESS)
    496     {
    497         TRACELOG(LOG_WARNING, "AUDIO: Failed to create mutex for mixing");
    498         ma_device_uninit(&AUDIO.System.device);
    499         ma_context_uninit(&AUDIO.System.context);
    500         return;
    501     }
    502 
    503     // Keep the device running the whole time. May want to consider doing something a bit smarter and only have the device running
    504     // while there's at least one sound being played
    505     result = ma_device_start(&AUDIO.System.device);
    506     if (result != MA_SUCCESS)
    507     {
    508         TRACELOG(LOG_WARNING, "AUDIO: Failed to start playback device");
    509         ma_device_uninit(&AUDIO.System.device);
    510         ma_context_uninit(&AUDIO.System.context);
    511         return;
    512     }
    513 
    514     TRACELOG(LOG_INFO, "AUDIO: Device initialized successfully");
    515     TRACELOG(LOG_INFO, "    > Backend:       miniaudio | %s", ma_get_backend_name(AUDIO.System.context.backend));
    516     TRACELOG(LOG_INFO, "    > Format:        %s -> %s", ma_get_format_name(AUDIO.System.device.playback.format), ma_get_format_name(AUDIO.System.device.playback.internalFormat));
    517     TRACELOG(LOG_INFO, "    > Channels:      %d -> %d", AUDIO.System.device.playback.channels, AUDIO.System.device.playback.internalChannels);
    518     TRACELOG(LOG_INFO, "    > Sample rate:   %d -> %d", AUDIO.System.device.sampleRate, AUDIO.System.device.playback.internalSampleRate);
    519     TRACELOG(LOG_INFO, "    > Periods size:  %d", AUDIO.System.device.playback.internalPeriodSizeInFrames*AUDIO.System.device.playback.internalPeriods);
    520 
    521     AUDIO.System.isReady = true;
    522 }
    523 
    524 // Close the audio device for all contexts
    525 void CloseAudioDevice(void)
    526 {
    527     if (AUDIO.System.isReady)
    528     {
    529         ma_mutex_uninit(&AUDIO.System.lock);
    530         ma_device_uninit(&AUDIO.System.device);
    531         ma_context_uninit(&AUDIO.System.context);
    532 
    533         AUDIO.System.isReady = false;
    534         RL_FREE(AUDIO.System.pcmBuffer);
    535         AUDIO.System.pcmBuffer = NULL;
    536         AUDIO.System.pcmBufferSize = 0;
    537 
    538         TRACELOG(LOG_INFO, "AUDIO: Device closed successfully");
    539     }
    540     else TRACELOG(LOG_WARNING, "AUDIO: Device could not be closed, not currently initialized");
    541 }
    542 
    543 // Check if device has been initialized successfully
    544 bool IsAudioDeviceReady(void)
    545 {
    546     return AUDIO.System.isReady;
    547 }
    548 
    549 // Set master volume (listener)
    550 void SetMasterVolume(float volume)
    551 {
    552     ma_device_set_master_volume(&AUDIO.System.device, volume);
    553 }
    554 
    555 // Get master volume (listener)
    556 float GetMasterVolume(void)
    557 {
    558     float volume = 0.0f;
    559     ma_device_get_master_volume(&AUDIO.System.device, &volume);
    560     return volume;
    561 }
    562 
    563 //----------------------------------------------------------------------------------
    564 // Module Functions Definition - Audio Buffer management
    565 //----------------------------------------------------------------------------------
    566 
    567 // Initialize a new audio buffer (filled with silence)
    568 AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 sizeInFrames, int usage)
    569 {
    570     AudioBuffer *audioBuffer = (AudioBuffer *)RL_CALLOC(1, sizeof(AudioBuffer));
    571 
    572     if (audioBuffer == NULL)
    573     {
    574         TRACELOG(LOG_WARNING, "AUDIO: Failed to allocate memory for buffer");
    575         return NULL;
    576     }
    577 
    578     if (sizeInFrames > 0) audioBuffer->data = RL_CALLOC(sizeInFrames*channels*ma_get_bytes_per_sample(format), 1);
    579 
    580     // Audio data runs through a format converter
    581     ma_data_converter_config converterConfig = ma_data_converter_config_init(format, AUDIO_DEVICE_FORMAT, channels, AUDIO_DEVICE_CHANNELS, sampleRate, AUDIO.System.device.sampleRate);
    582     converterConfig.allowDynamicSampleRate = true;
    583 
    584     ma_result result = ma_data_converter_init(&converterConfig, NULL, &audioBuffer->converter);
    585 
    586     if (result != MA_SUCCESS)
    587     {
    588         TRACELOG(LOG_WARNING, "AUDIO: Failed to create data conversion pipeline");
    589         RL_FREE(audioBuffer);
    590         return NULL;
    591     }
    592 
    593     // Init audio buffer values
    594     audioBuffer->volume = 1.0f;
    595     audioBuffer->pitch = 1.0f;
    596     audioBuffer->pan = 0.5f;
    597 
    598     audioBuffer->callback = NULL;
    599     audioBuffer->processor = NULL;
    600 
    601     audioBuffer->playing = false;
    602     audioBuffer->paused = false;
    603     audioBuffer->looping = false;
    604 
    605     audioBuffer->usage = usage;
    606     audioBuffer->frameCursorPos = 0;
    607     audioBuffer->sizeInFrames = sizeInFrames;
    608 
    609     // Buffers should be marked as processed by default so that a call to
    610     // UpdateAudioStream() immediately after initialization works correctly
    611     audioBuffer->isSubBufferProcessed[0] = true;
    612     audioBuffer->isSubBufferProcessed[1] = true;
    613 
    614     // Track audio buffer to linked list next position
    615     TrackAudioBuffer(audioBuffer);
    616 
    617     return audioBuffer;
    618 }
    619 
    620 // Delete an audio buffer
    621 void UnloadAudioBuffer(AudioBuffer *buffer)
    622 {
    623     if (buffer != NULL)
    624     {
    625         UntrackAudioBuffer(buffer);
    626         ma_data_converter_uninit(&buffer->converter, NULL);
    627         RL_FREE(buffer->data);
    628         RL_FREE(buffer);
    629     }
    630 }
    631 
    632 // Check if an audio buffer is playing from a program state without lock
    633 bool IsAudioBufferPlaying(AudioBuffer *buffer)
    634 {
    635     bool result = false;
    636     ma_mutex_lock(&AUDIO.System.lock);
    637     result = IsAudioBufferPlayingInLockedState(buffer);
    638     ma_mutex_unlock(&AUDIO.System.lock);
    639     return result;
    640 }
    641 
    642 // Play an audio buffer
    643 // NOTE: Buffer is restarted to the start
    644 // Use PauseAudioBuffer() and ResumeAudioBuffer() if the playback position should be maintained
    645 void PlayAudioBuffer(AudioBuffer *buffer)
    646 {
    647     if (buffer != NULL)
    648     {
    649         ma_mutex_lock(&AUDIO.System.lock);
    650         buffer->playing = true;
    651         buffer->paused = false;
    652         buffer->frameCursorPos = 0;
    653         ma_mutex_unlock(&AUDIO.System.lock);
    654     }
    655 }
    656 
    657 // Stop an audio buffer from a program state without lock
    658 void StopAudioBuffer(AudioBuffer *buffer)
    659 {
    660     ma_mutex_lock(&AUDIO.System.lock);
    661     StopAudioBufferInLockedState(buffer);
    662     ma_mutex_unlock(&AUDIO.System.lock);
    663 }
    664 
    665 // Pause an audio buffer
    666 void PauseAudioBuffer(AudioBuffer *buffer)
    667 {
    668     if (buffer != NULL)
    669     {
    670         ma_mutex_lock(&AUDIO.System.lock);
    671         buffer->paused = true;
    672         ma_mutex_unlock(&AUDIO.System.lock);
    673     }
    674 }
    675 
    676 // Resume an audio buffer
    677 void ResumeAudioBuffer(AudioBuffer *buffer)
    678 {
    679     if (buffer != NULL)
    680     {
    681         ma_mutex_lock(&AUDIO.System.lock);
    682         buffer->paused = false;
    683         ma_mutex_unlock(&AUDIO.System.lock);
    684     }
    685 }
    686 
    687 // Set volume for an audio buffer
    688 void SetAudioBufferVolume(AudioBuffer *buffer, float volume)
    689 {
    690     if (buffer != NULL)
    691     {
    692         ma_mutex_lock(&AUDIO.System.lock);
    693         buffer->volume = volume;
    694         ma_mutex_unlock(&AUDIO.System.lock);
    695     }
    696 }
    697 
    698 // Set pitch for an audio buffer
    699 void SetAudioBufferPitch(AudioBuffer *buffer, float pitch)
    700 {
    701     if ((buffer != NULL) && (pitch > 0.0f))
    702     {
    703         ma_mutex_lock(&AUDIO.System.lock);
    704         // Pitching is just an adjustment of the sample rate
    705         // Note that this changes the duration of the sound:
    706         //  - higher pitches will make the sound faster
    707         //  - lower pitches make it slower
    708         ma_uint32 outputSampleRate = (ma_uint32)((float)buffer->converter.sampleRateOut/pitch);
    709         ma_data_converter_set_rate(&buffer->converter, buffer->converter.sampleRateIn, outputSampleRate);
    710 
    711         buffer->pitch = pitch;
    712         ma_mutex_unlock(&AUDIO.System.lock);
    713     }
    714 }
    715 
    716 // Set pan for an audio buffer
    717 void SetAudioBufferPan(AudioBuffer *buffer, float pan)
    718 {
    719     if (pan < 0.0f) pan = 0.0f;
    720     else if (pan > 1.0f) pan = 1.0f;
    721 
    722     if (buffer != NULL)
    723     {
    724         ma_mutex_lock(&AUDIO.System.lock);
    725         buffer->pan = pan;
    726         ma_mutex_unlock(&AUDIO.System.lock);
    727     }
    728 }
    729 
    730 // Track audio buffer to linked list next position
    731 void TrackAudioBuffer(AudioBuffer *buffer)
    732 {
    733     ma_mutex_lock(&AUDIO.System.lock);
    734     {
    735         if (AUDIO.Buffer.first == NULL) AUDIO.Buffer.first = buffer;
    736         else
    737         {
    738             AUDIO.Buffer.last->next = buffer;
    739             buffer->prev = AUDIO.Buffer.last;
    740         }
    741 
    742         AUDIO.Buffer.last = buffer;
    743     }
    744     ma_mutex_unlock(&AUDIO.System.lock);
    745 }
    746 
    747 // Untrack audio buffer from linked list
    748 void UntrackAudioBuffer(AudioBuffer *buffer)
    749 {
    750     ma_mutex_lock(&AUDIO.System.lock);
    751     {
    752         if (buffer->prev == NULL) AUDIO.Buffer.first = buffer->next;
    753         else buffer->prev->next = buffer->next;
    754 
    755         if (buffer->next == NULL) AUDIO.Buffer.last = buffer->prev;
    756         else buffer->next->prev = buffer->prev;
    757 
    758         buffer->prev = NULL;
    759         buffer->next = NULL;
    760     }
    761     ma_mutex_unlock(&AUDIO.System.lock);
    762 }
    763 
    764 //----------------------------------------------------------------------------------
    765 // Module Functions Definition - Sounds loading and playing (.WAV)
    766 //----------------------------------------------------------------------------------
    767 
    768 // Load wave data from file
    769 Wave LoadWave(const char *fileName)
    770 {
    771     Wave wave = { 0 };
    772 
    773     // Loading file to memory
    774     int dataSize = 0;
    775     unsigned char *fileData = LoadFileData(fileName, &dataSize);
    776 
    777     // Loading wave from memory data
    778     if (fileData != NULL) wave = LoadWaveFromMemory(GetFileExtension(fileName), fileData, dataSize);
    779 
    780     UnloadFileData(fileData);
    781 
    782     return wave;
    783 }
    784 
    785 // Load wave from memory buffer, fileType refers to extension: i.e. ".wav"
    786 // WARNING: File extension must be provided in lower-case
    787 Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int dataSize)
    788 {
    789     Wave wave = { 0 };
    790 
    791     if (false) { }
    792 #if defined(SUPPORT_FILEFORMAT_WAV)
    793     else if ((strcmp(fileType, ".wav") == 0) || (strcmp(fileType, ".WAV") == 0))
    794     {
    795         drwav wav = { 0 };
    796         bool success = drwav_init_memory(&wav, fileData, dataSize, NULL);
    797 
    798         if (success)
    799         {
    800             wave.frameCount = (unsigned int)wav.totalPCMFrameCount;
    801             wave.sampleRate = wav.sampleRate;
    802             wave.sampleSize = 16;
    803             wave.channels = wav.channels;
    804             wave.data = (short *)RL_MALLOC(wave.frameCount*wave.channels*sizeof(short));
    805 
    806             // NOTE: We are forcing conversion to 16bit sample size on reading
    807             drwav_read_pcm_frames_s16(&wav, wav.totalPCMFrameCount, wave.data);
    808         }
    809         else TRACELOG(LOG_WARNING, "WAVE: Failed to load WAV data");
    810 
    811         drwav_uninit(&wav);
    812     }
    813 #endif
    814 #if defined(SUPPORT_FILEFORMAT_OGG)
    815     else if ((strcmp(fileType, ".ogg") == 0) || (strcmp(fileType, ".OGG") == 0))
    816     {
    817         stb_vorbis *oggData = stb_vorbis_open_memory((unsigned char *)fileData, dataSize, NULL, NULL);
    818 
    819         if (oggData != NULL)
    820         {
    821             stb_vorbis_info info = stb_vorbis_get_info(oggData);
    822 
    823             wave.sampleRate = info.sample_rate;
    824             wave.sampleSize = 16;       // By default, ogg data is 16 bit per sample (short)
    825             wave.channels = info.channels;
    826             wave.frameCount = (unsigned int)stb_vorbis_stream_length_in_samples(oggData);  // NOTE: It returns frames!
    827             wave.data = (short *)RL_MALLOC(wave.frameCount*wave.channels*sizeof(short));
    828 
    829             // NOTE: Get the number of samples to process (be careful! we ask for number of shorts, not bytes!)
    830             stb_vorbis_get_samples_short_interleaved(oggData, info.channels, (short *)wave.data, wave.frameCount*wave.channels);
    831             stb_vorbis_close(oggData);
    832         }
    833         else TRACELOG(LOG_WARNING, "WAVE: Failed to load OGG data");
    834     }
    835 #endif
    836 #if defined(SUPPORT_FILEFORMAT_MP3)
    837     else if ((strcmp(fileType, ".mp3") == 0) || (strcmp(fileType, ".MP3") == 0))
    838     {
    839         drmp3_config config = { 0 };
    840         unsigned long long int totalFrameCount = 0;
    841 
    842         // NOTE: We are forcing conversion to 32bit float sample size on reading
    843         wave.data = drmp3_open_memory_and_read_pcm_frames_f32(fileData, dataSize, &config, &totalFrameCount, NULL);
    844         wave.sampleSize = 32;
    845 
    846         if (wave.data != NULL)
    847         {
    848             wave.channels = config.channels;
    849             wave.sampleRate = config.sampleRate;
    850             wave.frameCount = (int)totalFrameCount;
    851         }
    852         else TRACELOG(LOG_WARNING, "WAVE: Failed to load MP3 data");
    853 
    854     }
    855 #endif
    856 #if defined(SUPPORT_FILEFORMAT_QOA)
    857     else if ((strcmp(fileType, ".qoa") == 0) || (strcmp(fileType, ".QOA") == 0))
    858     {
    859         qoa_desc qoa = { 0 };
    860 
    861         // NOTE: Returned sample data is always 16 bit?
    862         wave.data = qoa_decode(fileData, dataSize, &qoa);
    863         wave.sampleSize = 16;
    864 
    865         if (wave.data != NULL)
    866         {
    867             wave.channels = qoa.channels;
    868             wave.sampleRate = qoa.samplerate;
    869             wave.frameCount = qoa.samples;
    870         }
    871         else TRACELOG(LOG_WARNING, "WAVE: Failed to load QOA data");
    872 
    873     }
    874 #endif
    875 #if defined(SUPPORT_FILEFORMAT_FLAC)
    876     else if ((strcmp(fileType, ".flac") == 0) || (strcmp(fileType, ".FLAC") == 0))
    877     {
    878         unsigned long long int totalFrameCount = 0;
    879 
    880         // NOTE: We are forcing conversion to 16bit sample size on reading
    881         wave.data = drflac_open_memory_and_read_pcm_frames_s16(fileData, dataSize, &wave.channels, &wave.sampleRate, &totalFrameCount, NULL);
    882         wave.sampleSize = 16;
    883 
    884         if (wave.data != NULL) wave.frameCount = (unsigned int)totalFrameCount;
    885         else TRACELOG(LOG_WARNING, "WAVE: Failed to load FLAC data");
    886     }
    887 #endif
    888     else TRACELOG(LOG_WARNING, "WAVE: Data format not supported");
    889 
    890     TRACELOG(LOG_INFO, "WAVE: Data loaded successfully (%i Hz, %i bit, %i channels)", wave.sampleRate, wave.sampleSize, wave.channels);
    891 
    892     return wave;
    893 }
    894 
    895 // Checks if wave data is valid (data loaded and parameters)
    896 bool IsWaveValid(Wave wave)
    897 {
    898     bool result = false;
    899 
    900     if ((wave.data != NULL) &&      // Validate wave data available
    901         (wave.frameCount > 0) &&    // Validate frame count
    902         (wave.sampleRate > 0) &&    // Validate sample rate is supported
    903         (wave.sampleSize > 0) &&    // Validate sample size is supported
    904         (wave.channels > 0)) result = true; // Validate number of channels supported
    905 
    906     return result;
    907 }
    908 
    909 // Load sound from file
    910 // NOTE: The entire file is loaded to memory to be played (no-streaming)
    911 Sound LoadSound(const char *fileName)
    912 {
    913     Wave wave = LoadWave(fileName);
    914 
    915     Sound sound = LoadSoundFromWave(wave);
    916 
    917     UnloadWave(wave);       // Sound is loaded, we can unload wave
    918 
    919     return sound;
    920 }
    921 
    922 // Load sound from wave data
    923 // NOTE: Wave data must be unallocated manually
    924 Sound LoadSoundFromWave(Wave wave)
    925 {
    926     Sound sound = { 0 };
    927 
    928     if (wave.data != NULL)
    929     {
    930         // When using miniaudio we need to do our own mixing
    931         // To simplify this we need convert the format of each sound to be consistent with
    932         // the format used to open the playback AUDIO.System.device. We can do this two ways:
    933         //
    934         //   1) Convert the whole sound in one go at load time (here)
    935         //   2) Convert the audio data in chunks at mixing time
    936         //
    937         // First option has been selected, format conversion is done on the loading stage
    938         // The downside is that it uses more memory if the original sound is u8 or s16
    939         ma_format formatIn = ((wave.sampleSize == 8)? ma_format_u8 : ((wave.sampleSize == 16)? ma_format_s16 : ma_format_f32));
    940         ma_uint32 frameCountIn = wave.frameCount;
    941 
    942         ma_uint32 frameCount = (ma_uint32)ma_convert_frames(NULL, 0, AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO.System.device.sampleRate, NULL, frameCountIn, formatIn, wave.channels, wave.sampleRate);
    943         if (frameCount == 0) TRACELOG(LOG_WARNING, "SOUND: Failed to get frame count for format conversion");
    944 
    945         AudioBuffer *audioBuffer = LoadAudioBuffer(AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO.System.device.sampleRate, frameCount, AUDIO_BUFFER_USAGE_STATIC);
    946         if (audioBuffer == NULL)
    947         {
    948             TRACELOG(LOG_WARNING, "SOUND: Failed to create buffer");
    949             return sound; // early return to avoid dereferencing the audioBuffer null pointer
    950         }
    951 
    952         frameCount = (ma_uint32)ma_convert_frames(audioBuffer->data, frameCount, AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO.System.device.sampleRate, wave.data, frameCountIn, formatIn, wave.channels, wave.sampleRate);
    953         if (frameCount == 0) TRACELOG(LOG_WARNING, "SOUND: Failed format conversion");
    954 
    955         sound.frameCount = frameCount;
    956         sound.stream.sampleRate = AUDIO.System.device.sampleRate;
    957         sound.stream.sampleSize = 32;
    958         sound.stream.channels = AUDIO_DEVICE_CHANNELS;
    959         sound.stream.buffer = audioBuffer;
    960     }
    961 
    962     return sound;
    963 }
    964 
    965 // Clone sound from existing sound data, clone does not own wave data
    966 // NOTE: Wave data must be unallocated manually and will be shared across all clones
    967 Sound LoadSoundAlias(Sound source)
    968 {
    969     Sound sound = { 0 };
    970 
    971     if (source.stream.buffer->data != NULL)
    972     {
    973         AudioBuffer *audioBuffer = LoadAudioBuffer(AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO.System.device.sampleRate, 0, AUDIO_BUFFER_USAGE_STATIC);
    974 
    975         if (audioBuffer == NULL)
    976         {
    977             TRACELOG(LOG_WARNING, "SOUND: Failed to create buffer");
    978             return sound; // Early return to avoid dereferencing the audioBuffer null pointer
    979         }
    980 
    981         audioBuffer->sizeInFrames = source.stream.buffer->sizeInFrames;
    982         audioBuffer->volume = source.stream.buffer->volume;
    983         audioBuffer->data = source.stream.buffer->data;
    984 
    985         sound.frameCount = source.frameCount;
    986         sound.stream.sampleRate = AUDIO.System.device.sampleRate;
    987         sound.stream.sampleSize = 32;
    988         sound.stream.channels = AUDIO_DEVICE_CHANNELS;
    989         sound.stream.buffer = audioBuffer;
    990     }
    991 
    992     return sound;
    993 }
    994 
    995 
    996 // Checks if a sound is valid (data loaded and buffers initialized)
    997 bool IsSoundValid(Sound sound)
    998 {
    999     bool result = false;
   1000 
   1001     if ((sound.frameCount > 0) &&           // Validate frame count
   1002         (sound.stream.buffer != NULL) &&    // Validate stream buffer
   1003         (sound.stream.sampleRate > 0) &&    // Validate sample rate is supported
   1004         (sound.stream.sampleSize > 0) &&    // Validate sample size is supported
   1005         (sound.stream.channels > 0)) result = true; // Validate number of channels supported
   1006 
   1007     return result;
   1008 }
   1009 
   1010 // Unload wave data
   1011 void UnloadWave(Wave wave)
   1012 {
   1013     RL_FREE(wave.data);
   1014     //TRACELOG(LOG_INFO, "WAVE: Unloaded wave data from RAM");
   1015 }
   1016 
   1017 // Unload sound
   1018 void UnloadSound(Sound sound)
   1019 {
   1020     UnloadAudioBuffer(sound.stream.buffer);
   1021     //TRACELOG(LOG_INFO, "SOUND: Unloaded sound data from RAM");
   1022 }
   1023 
   1024 void UnloadSoundAlias(Sound alias)
   1025 {
   1026     // Untrack and unload just the sound buffer, not the sample data, it is shared with the source for the alias
   1027     if (alias.stream.buffer != NULL)
   1028     {
   1029         UntrackAudioBuffer(alias.stream.buffer);
   1030         ma_data_converter_uninit(&alias.stream.buffer->converter, NULL);
   1031         RL_FREE(alias.stream.buffer);
   1032     }
   1033 }
   1034 
   1035 // Update sound buffer with new data
   1036 void UpdateSound(Sound sound, const void *data, int frameCount)
   1037 {
   1038     if (sound.stream.buffer != NULL)
   1039     {
   1040         StopAudioBuffer(sound.stream.buffer);
   1041 
   1042         memcpy(sound.stream.buffer->data, data, frameCount*ma_get_bytes_per_frame(sound.stream.buffer->converter.formatIn, sound.stream.buffer->converter.channelsIn));
   1043     }
   1044 }
   1045 
   1046 // Export wave data to file
   1047 bool ExportWave(Wave wave, const char *fileName)
   1048 {
   1049     bool success = false;
   1050 
   1051     if (false) { }
   1052 #if defined(SUPPORT_FILEFORMAT_WAV)
   1053     else if (IsFileExtension(fileName, ".wav"))
   1054     {
   1055         drwav wav = { 0 };
   1056         drwav_data_format format = { 0 };
   1057         format.container = drwav_container_riff;
   1058         if (wave.sampleSize == 32) format.format = DR_WAVE_FORMAT_IEEE_FLOAT;
   1059         else format.format = DR_WAVE_FORMAT_PCM;
   1060         format.channels = wave.channels;
   1061         format.sampleRate = wave.sampleRate;
   1062         format.bitsPerSample = wave.sampleSize;
   1063 
   1064         void *fileData = NULL;
   1065         size_t fileDataSize = 0;
   1066         success = drwav_init_memory_write(&wav, &fileData, &fileDataSize, &format, NULL);
   1067         if (success) success = (int)drwav_write_pcm_frames(&wav, wave.frameCount, wave.data);
   1068         drwav_result result = drwav_uninit(&wav);
   1069 
   1070         if (result == DRWAV_SUCCESS) success = SaveFileData(fileName, (unsigned char *)fileData, (unsigned int)fileDataSize);
   1071 
   1072         drwav_free(fileData, NULL);
   1073     }
   1074 #endif
   1075 #if defined(SUPPORT_FILEFORMAT_QOA)
   1076     else if (IsFileExtension(fileName, ".qoa"))
   1077     {
   1078         if (wave.sampleSize == 16)
   1079         {
   1080             qoa_desc qoa = { 0 };
   1081             qoa.channels = wave.channels;
   1082             qoa.samplerate = wave.sampleRate;
   1083             qoa.samples = wave.frameCount;
   1084 
   1085             int bytesWritten = qoa_write(fileName, wave.data, &qoa);
   1086             if (bytesWritten > 0) success = true;
   1087         }
   1088         else TRACELOG(LOG_WARNING, "AUDIO: Wave data must be 16 bit per sample for QOA format export");
   1089     }
   1090 #endif
   1091     else if (IsFileExtension(fileName, ".raw"))
   1092     {
   1093         // Export raw sample data (without header)
   1094         // NOTE: It's up to the user to track wave parameters
   1095         success = SaveFileData(fileName, wave.data, wave.frameCount*wave.channels*wave.sampleSize/8);
   1096     }
   1097 
   1098     if (success) TRACELOG(LOG_INFO, "FILEIO: [%s] Wave data exported successfully", fileName);
   1099     else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export wave data", fileName);
   1100 
   1101     return success;
   1102 }
   1103 
   1104 // Export wave sample data to code (.h)
   1105 bool ExportWaveAsCode(Wave wave, const char *fileName)
   1106 {
   1107     bool success = false;
   1108 
   1109 #ifndef TEXT_BYTES_PER_LINE
   1110     #define TEXT_BYTES_PER_LINE     20
   1111 #endif
   1112 
   1113     int waveDataSize = wave.frameCount*wave.channels*wave.sampleSize/8;
   1114 
   1115     // NOTE: Text data buffer size is estimated considering wave data size in bytes
   1116     // and requiring 12 char bytes for every byte; the actual size varies, but
   1117     // the longest possible char being appended is "%.4ff,\n    ", which is 12 bytes.
   1118     char *txtData = (char *)RL_CALLOC(waveDataSize*12 + 2000, sizeof(char));
   1119 
   1120     int byteCount = 0;
   1121     byteCount += sprintf(txtData + byteCount, "\n//////////////////////////////////////////////////////////////////////////////////\n");
   1122     byteCount += sprintf(txtData + byteCount, "//                                                                              //\n");
   1123     byteCount += sprintf(txtData + byteCount, "// WaveAsCode exporter v1.1 - Wave data exported as an array of bytes           //\n");
   1124     byteCount += sprintf(txtData + byteCount, "//                                                                              //\n");
   1125     byteCount += sprintf(txtData + byteCount, "// more info and bugs-report:  github.com/raysan5/raylib                        //\n");
   1126     byteCount += sprintf(txtData + byteCount, "// feedback and support:       ray[at]raylib.com                                //\n");
   1127     byteCount += sprintf(txtData + byteCount, "//                                                                              //\n");
   1128     byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2024 Ramon Santamaria (@raysan5)                          //\n");
   1129     byteCount += sprintf(txtData + byteCount, "//                                                                              //\n");
   1130     byteCount += sprintf(txtData + byteCount, "//////////////////////////////////////////////////////////////////////////////////\n\n");
   1131 
   1132     // Get file name from path and convert variable name to uppercase
   1133     char varFileName[256] = { 0 };
   1134     strcpy(varFileName, GetFileNameWithoutExt(fileName));
   1135     for (int i = 0; varFileName[i] != '\0'; i++) if (varFileName[i] >= 'a' && varFileName[i] <= 'z') { varFileName[i] = varFileName[i] - 32; }
   1136 
   1137     // Add wave information
   1138     byteCount += sprintf(txtData + byteCount, "// Wave data information\n");
   1139     byteCount += sprintf(txtData + byteCount, "#define %s_FRAME_COUNT      %u\n", varFileName, wave.frameCount);
   1140     byteCount += sprintf(txtData + byteCount, "#define %s_SAMPLE_RATE      %u\n", varFileName, wave.sampleRate);
   1141     byteCount += sprintf(txtData + byteCount, "#define %s_SAMPLE_SIZE      %u\n", varFileName, wave.sampleSize);
   1142     byteCount += sprintf(txtData + byteCount, "#define %s_CHANNELS         %u\n\n", varFileName, wave.channels);
   1143 
   1144     // Write wave data as an array of values
   1145     // Wave data is exported as byte array for 8/16bit and float array for 32bit float data
   1146     // NOTE: Frame data exported is channel-interlaced: frame01[sampleChannel1, sampleChannel2, ...], frame02[], frame03[]
   1147     if (wave.sampleSize == 32)
   1148     {
   1149         byteCount += sprintf(txtData + byteCount, "static float %s_DATA[%i] = {\n", varFileName, waveDataSize/4);
   1150         for (int i = 1; i < waveDataSize/4; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "%.4ff,\n    " : "%.4ff, "), ((float *)wave.data)[i - 1]);
   1151         byteCount += sprintf(txtData + byteCount, "%.4ff };\n", ((float *)wave.data)[waveDataSize/4 - 1]);
   1152     }
   1153     else
   1154     {
   1155         byteCount += sprintf(txtData + byteCount, "static unsigned char %s_DATA[%i] = { ", varFileName, waveDataSize);
   1156         for (int i = 1; i < waveDataSize; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%x,\n    " : "0x%x, "), ((unsigned char *)wave.data)[i - 1]);
   1157         byteCount += sprintf(txtData + byteCount, "0x%x };\n", ((unsigned char *)wave.data)[waveDataSize - 1]);
   1158     }
   1159 
   1160     // NOTE: Text data length exported is determined by '\0' (NULL) character
   1161     success = SaveFileText(fileName, txtData);
   1162 
   1163     RL_FREE(txtData);
   1164 
   1165     if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Wave as code exported successfully", fileName);
   1166     else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export wave as code", fileName);
   1167 
   1168     return success;
   1169 }
   1170 
   1171 // Play a sound
   1172 void PlaySound(Sound sound)
   1173 {
   1174     PlayAudioBuffer(sound.stream.buffer);
   1175 }
   1176 
   1177 // Pause a sound
   1178 void PauseSound(Sound sound)
   1179 {
   1180     PauseAudioBuffer(sound.stream.buffer);
   1181 }
   1182 
   1183 // Resume a paused sound
   1184 void ResumeSound(Sound sound)
   1185 {
   1186     ResumeAudioBuffer(sound.stream.buffer);
   1187 }
   1188 
   1189 // Stop reproducing a sound
   1190 void StopSound(Sound sound)
   1191 {
   1192     StopAudioBuffer(sound.stream.buffer);
   1193 }
   1194 
   1195 // Check if a sound is playing
   1196 bool IsSoundPlaying(Sound sound)
   1197 {
   1198     bool result = false;
   1199 
   1200     if (IsAudioBufferPlaying(sound.stream.buffer)) result = true;
   1201 
   1202     return result;
   1203 }
   1204 
   1205 // Set volume for a sound
   1206 void SetSoundVolume(Sound sound, float volume)
   1207 {
   1208     SetAudioBufferVolume(sound.stream.buffer, volume);
   1209 }
   1210 
   1211 // Set pitch for a sound
   1212 void SetSoundPitch(Sound sound, float pitch)
   1213 {
   1214     SetAudioBufferPitch(sound.stream.buffer, pitch);
   1215 }
   1216 
   1217 // Set pan for a sound
   1218 void SetSoundPan(Sound sound, float pan)
   1219 {
   1220     SetAudioBufferPan(sound.stream.buffer, pan);
   1221 }
   1222 
   1223 // Convert wave data to desired format
   1224 void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels)
   1225 {
   1226     ma_format formatIn = ((wave->sampleSize == 8)? ma_format_u8 : ((wave->sampleSize == 16)? ma_format_s16 : ma_format_f32));
   1227     ma_format formatOut = ((sampleSize == 8)? ma_format_u8 : ((sampleSize == 16)? ma_format_s16 : ma_format_f32));
   1228 
   1229     ma_uint32 frameCountIn = wave->frameCount;
   1230     ma_uint32 frameCount = (ma_uint32)ma_convert_frames(NULL, 0, formatOut, channels, sampleRate, NULL, frameCountIn, formatIn, wave->channels, wave->sampleRate);
   1231 
   1232     if (frameCount == 0)
   1233     {
   1234         TRACELOG(LOG_WARNING, "WAVE: Failed to get frame count for format conversion");
   1235         return;
   1236     }
   1237 
   1238     void *data = RL_MALLOC(frameCount*channels*(sampleSize/8));
   1239 
   1240     frameCount = (ma_uint32)ma_convert_frames(data, frameCount, formatOut, channels, sampleRate, wave->data, frameCountIn, formatIn, wave->channels, wave->sampleRate);
   1241     if (frameCount == 0)
   1242     {
   1243         TRACELOG(LOG_WARNING, "WAVE: Failed format conversion");
   1244         return;
   1245     }
   1246 
   1247     wave->frameCount = frameCount;
   1248     wave->sampleSize = sampleSize;
   1249     wave->sampleRate = sampleRate;
   1250     wave->channels = channels;
   1251 
   1252     RL_FREE(wave->data);
   1253     wave->data = data;
   1254 }
   1255 
   1256 // Copy a wave to a new wave
   1257 Wave WaveCopy(Wave wave)
   1258 {
   1259     Wave newWave = { 0 };
   1260 
   1261     newWave.data = RL_MALLOC(wave.frameCount*wave.channels*wave.sampleSize/8);
   1262 
   1263     if (newWave.data != NULL)
   1264     {
   1265         // NOTE: Size must be provided in bytes
   1266         memcpy(newWave.data, wave.data, wave.frameCount*wave.channels*wave.sampleSize/8);
   1267 
   1268         newWave.frameCount = wave.frameCount;
   1269         newWave.sampleRate = wave.sampleRate;
   1270         newWave.sampleSize = wave.sampleSize;
   1271         newWave.channels = wave.channels;
   1272     }
   1273 
   1274     return newWave;
   1275 }
   1276 
   1277 // Crop a wave to defined frames range
   1278 // NOTE: Security check in case of out-of-range
   1279 void WaveCrop(Wave *wave, int initFrame, int finalFrame)
   1280 {
   1281     if ((initFrame >= 0) && (initFrame < finalFrame) && ((unsigned int)finalFrame <= wave->frameCount))
   1282     {
   1283         int frameCount = finalFrame - initFrame;
   1284 
   1285         void *data = RL_MALLOC(frameCount*wave->channels*wave->sampleSize/8);
   1286 
   1287         memcpy(data, (unsigned char *)wave->data + (initFrame*wave->channels*wave->sampleSize/8), frameCount*wave->channels*wave->sampleSize/8);
   1288 
   1289         RL_FREE(wave->data);
   1290         wave->data = data;
   1291         wave->frameCount = (unsigned int)frameCount;
   1292     }
   1293     else TRACELOG(LOG_WARNING, "WAVE: Crop range out of bounds");
   1294 }
   1295 
   1296 // Load samples data from wave as a floats array
   1297 // NOTE 1: Returned sample values are normalized to range [-1..1]
   1298 // NOTE 2: Sample data allocated should be freed with UnloadWaveSamples()
   1299 float *LoadWaveSamples(Wave wave)
   1300 {
   1301     float *samples = (float *)RL_MALLOC(wave.frameCount*wave.channels*sizeof(float));
   1302 
   1303     // NOTE: sampleCount is the total number of interlaced samples (including channels)
   1304 
   1305     for (unsigned int i = 0; i < wave.frameCount*wave.channels; i++)
   1306     {
   1307         if (wave.sampleSize == 8) samples[i] = (float)(((unsigned char *)wave.data)[i] - 128)/128.0f;
   1308         else if (wave.sampleSize == 16) samples[i] = (float)(((short *)wave.data)[i])/32768.0f;
   1309         else if (wave.sampleSize == 32) samples[i] = ((float *)wave.data)[i];
   1310     }
   1311 
   1312     return samples;
   1313 }
   1314 
   1315 // Unload samples data loaded with LoadWaveSamples()
   1316 void UnloadWaveSamples(float *samples)
   1317 {
   1318     RL_FREE(samples);
   1319 }
   1320 
   1321 //----------------------------------------------------------------------------------
   1322 // Module Functions Definition - Music loading and stream playing
   1323 //----------------------------------------------------------------------------------
   1324 
   1325 // Load music stream from file
   1326 Music LoadMusicStream(const char *fileName)
   1327 {
   1328     Music music = { 0 };
   1329     bool musicLoaded = false;
   1330 
   1331     if (false) { }
   1332 #if defined(SUPPORT_FILEFORMAT_WAV)
   1333     else if (IsFileExtension(fileName, ".wav"))
   1334     {
   1335         drwav *ctxWav = RL_CALLOC(1, sizeof(drwav));
   1336         bool success = drwav_init_file(ctxWav, fileName, NULL);
   1337 
   1338         if (success)
   1339         {
   1340             music.ctxType = MUSIC_AUDIO_WAV;
   1341             music.ctxData = ctxWav;
   1342             int sampleSize = ctxWav->bitsPerSample;
   1343             if (ctxWav->bitsPerSample == 24) sampleSize = 16;   // Forcing conversion to s16 on UpdateMusicStream()
   1344 
   1345             music.stream = LoadAudioStream(ctxWav->sampleRate, sampleSize, ctxWav->channels);
   1346             music.frameCount = (unsigned int)ctxWav->totalPCMFrameCount;
   1347             music.looping = true;   // Looping enabled by default
   1348             musicLoaded = true;
   1349         }
   1350         else
   1351         {
   1352             RL_FREE(ctxWav);
   1353         }
   1354     }
   1355 #endif
   1356 #if defined(SUPPORT_FILEFORMAT_OGG)
   1357     else if (IsFileExtension(fileName, ".ogg"))
   1358     {
   1359         // Open ogg audio stream
   1360         stb_vorbis *ctxOgg = stb_vorbis_open_filename(fileName, NULL, NULL);
   1361 
   1362         if (ctxOgg != NULL)
   1363         {
   1364             music.ctxType = MUSIC_AUDIO_OGG;
   1365             music.ctxData = ctxOgg;
   1366             stb_vorbis_info info = stb_vorbis_get_info((stb_vorbis *)music.ctxData);  // Get Ogg file info
   1367 
   1368             // OGG bit rate defaults to 16 bit, it's enough for compressed format
   1369             music.stream = LoadAudioStream(info.sample_rate, 16, info.channels);
   1370 
   1371             // WARNING: It seems this function returns length in frames, not samples, so we multiply by channels
   1372             music.frameCount = (unsigned int)stb_vorbis_stream_length_in_samples((stb_vorbis *)music.ctxData);
   1373             music.looping = true;   // Looping enabled by default
   1374             musicLoaded = true;
   1375         }
   1376         else
   1377         {
   1378             stb_vorbis_close(ctxOgg);
   1379         }
   1380     }
   1381 #endif
   1382 #if defined(SUPPORT_FILEFORMAT_MP3)
   1383     else if (IsFileExtension(fileName, ".mp3"))
   1384     {
   1385         drmp3 *ctxMp3 = RL_CALLOC(1, sizeof(drmp3));
   1386         int result = drmp3_init_file(ctxMp3, fileName, NULL);
   1387 
   1388         if (result > 0)
   1389         {
   1390             music.ctxType = MUSIC_AUDIO_MP3;
   1391             music.ctxData = ctxMp3;
   1392             music.stream = LoadAudioStream(ctxMp3->sampleRate, 32, ctxMp3->channels);
   1393             music.frameCount = (unsigned int)drmp3_get_pcm_frame_count(ctxMp3);
   1394             music.looping = true;   // Looping enabled by default
   1395             musicLoaded = true;
   1396         }
   1397         else
   1398         {
   1399             RL_FREE(ctxMp3);
   1400         }
   1401     }
   1402 #endif
   1403 #if defined(SUPPORT_FILEFORMAT_QOA)
   1404     else if (IsFileExtension(fileName, ".qoa"))
   1405     {
   1406         qoaplay_desc *ctxQoa = qoaplay_open(fileName);
   1407 
   1408         if (ctxQoa != NULL)
   1409         {
   1410             music.ctxType = MUSIC_AUDIO_QOA;
   1411             music.ctxData = ctxQoa;
   1412             // NOTE: We are loading samples are 32bit float normalized data, so,
   1413             // we configure the output audio stream to also use float 32bit
   1414             music.stream = LoadAudioStream(ctxQoa->info.samplerate, 32, ctxQoa->info.channels);
   1415             music.frameCount = ctxQoa->info.samples;
   1416             music.looping = true;   // Looping enabled by default
   1417             musicLoaded = true;
   1418         }
   1419         else{} //No uninit required
   1420     }
   1421 #endif
   1422 #if defined(SUPPORT_FILEFORMAT_FLAC)
   1423     else if (IsFileExtension(fileName, ".flac"))
   1424     {
   1425         drflac *ctxFlac = drflac_open_file(fileName, NULL);
   1426 
   1427         if (ctxFlac != NULL)
   1428         {
   1429             music.ctxType = MUSIC_AUDIO_FLAC;
   1430             music.ctxData = ctxFlac;
   1431             int sampleSize = ctxFlac->bitsPerSample;
   1432             if (ctxFlac->bitsPerSample == 24) sampleSize = 16;   // Forcing conversion to s16 on UpdateMusicStream()
   1433             music.stream = LoadAudioStream(ctxFlac->sampleRate, sampleSize, ctxFlac->channels);
   1434             music.frameCount = (unsigned int)ctxFlac->totalPCMFrameCount;
   1435             music.looping = true;   // Looping enabled by default
   1436             musicLoaded = true;
   1437         }
   1438         else
   1439         {
   1440             drflac_free(ctxFlac, NULL);
   1441         }
   1442     }
   1443 #endif
   1444 #if defined(SUPPORT_FILEFORMAT_XM)
   1445     else if (IsFileExtension(fileName, ".xm"))
   1446     {
   1447         jar_xm_context_t *ctxXm = NULL;
   1448         int result = jar_xm_create_context_from_file(&ctxXm, AUDIO.System.device.sampleRate, fileName);
   1449 
   1450         if (result == 0)    // XM AUDIO.System.context created successfully
   1451         {
   1452             music.ctxType = MUSIC_MODULE_XM;
   1453             music.ctxData = ctxXm;
   1454             jar_xm_set_max_loop_count(ctxXm, 0);    // Set infinite number of loops
   1455 
   1456             unsigned int bits = 32;
   1457             if (AUDIO_DEVICE_FORMAT == ma_format_s16) bits = 16;
   1458             else if (AUDIO_DEVICE_FORMAT == ma_format_u8) bits = 8;
   1459 
   1460             // NOTE: Only stereo is supported for XM
   1461             music.stream = LoadAudioStream(AUDIO.System.device.sampleRate, bits, AUDIO_DEVICE_CHANNELS);
   1462             music.frameCount = (unsigned int)jar_xm_get_remaining_samples(ctxXm);    // NOTE: Always 2 channels (stereo)
   1463             music.looping = true;   // Looping enabled by default
   1464             jar_xm_reset(ctxXm);    // Make sure we start at the beginning of the song
   1465             musicLoaded = true;
   1466         }
   1467         else
   1468         {
   1469             jar_xm_free_context(ctxXm);
   1470         }
   1471     }
   1472 #endif
   1473 #if defined(SUPPORT_FILEFORMAT_MOD)
   1474     else if (IsFileExtension(fileName, ".mod"))
   1475     {
   1476         jar_mod_context_t *ctxMod = RL_CALLOC(1, sizeof(jar_mod_context_t));
   1477         jar_mod_init(ctxMod);
   1478         int result = jar_mod_load_file(ctxMod, fileName);
   1479 
   1480         if (result > 0)
   1481         {
   1482             music.ctxType = MUSIC_MODULE_MOD;
   1483             music.ctxData = ctxMod;
   1484             // NOTE: Only stereo is supported for MOD
   1485             music.stream = LoadAudioStream(AUDIO.System.device.sampleRate, 16, AUDIO_DEVICE_CHANNELS);
   1486             music.frameCount = (unsigned int)jar_mod_max_samples(ctxMod);    // NOTE: Always 2 channels (stereo)
   1487             music.looping = true;   // Looping enabled by default
   1488             musicLoaded = true;
   1489         }
   1490         else
   1491         {
   1492             jar_mod_unload(ctxMod);
   1493             RL_FREE(ctxMod);
   1494         }
   1495     }
   1496 #endif
   1497     else TRACELOG(LOG_WARNING, "STREAM: [%s] File format not supported", fileName);
   1498 
   1499     if (!musicLoaded)
   1500     {
   1501         TRACELOG(LOG_WARNING, "FILEIO: [%s] Music file could not be opened", fileName);
   1502     }
   1503     else
   1504     {
   1505         // Show some music stream info
   1506         TRACELOG(LOG_INFO, "FILEIO: [%s] Music file loaded successfully", fileName);
   1507         TRACELOG(LOG_INFO, "    > Sample rate:   %i Hz", music.stream.sampleRate);
   1508         TRACELOG(LOG_INFO, "    > Sample size:   %i bits", music.stream.sampleSize);
   1509         TRACELOG(LOG_INFO, "    > Channels:      %i (%s)", music.stream.channels, (music.stream.channels == 1)? "Mono" : (music.stream.channels == 2)? "Stereo" : "Multi");
   1510         TRACELOG(LOG_INFO, "    > Total frames:  %i", music.frameCount);
   1511     }
   1512 
   1513     return music;
   1514 }
   1515 
   1516 // Load music stream from memory buffer, fileType refers to extension: i.e. ".wav"
   1517 // WARNING: File extension must be provided in lower-case
   1518 Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, int dataSize)
   1519 {
   1520     Music music = { 0 };
   1521     bool musicLoaded = false;
   1522 
   1523     if (false) { }
   1524 #if defined(SUPPORT_FILEFORMAT_WAV)
   1525     else if ((strcmp(fileType, ".wav") == 0) || (strcmp(fileType, ".WAV") == 0))
   1526     {
   1527         drwav *ctxWav = RL_CALLOC(1, sizeof(drwav));
   1528 
   1529         bool success = drwav_init_memory(ctxWav, (const void *)data, dataSize, NULL);
   1530 
   1531         if (success)
   1532         {
   1533             music.ctxType = MUSIC_AUDIO_WAV;
   1534             music.ctxData = ctxWav;
   1535             int sampleSize = ctxWav->bitsPerSample;
   1536             if (ctxWav->bitsPerSample == 24) sampleSize = 16;   // Forcing conversion to s16 on UpdateMusicStream()
   1537 
   1538             music.stream = LoadAudioStream(ctxWav->sampleRate, sampleSize, ctxWav->channels);
   1539             music.frameCount = (unsigned int)ctxWav->totalPCMFrameCount;
   1540             music.looping = true;   // Looping enabled by default
   1541             musicLoaded = true;
   1542         }
   1543         else {
   1544             drwav_uninit(ctxWav);
   1545             RL_FREE(ctxWav);
   1546         }
   1547     }
   1548 #endif
   1549 #if defined(SUPPORT_FILEFORMAT_OGG)
   1550     else if ((strcmp(fileType, ".ogg") == 0) || (strcmp(fileType, ".OGG") == 0))
   1551     {
   1552         // Open ogg audio stream
   1553         stb_vorbis* ctxOgg = stb_vorbis_open_memory((const unsigned char *)data, dataSize, NULL, NULL);
   1554 
   1555         if (ctxOgg != NULL)
   1556         {
   1557             music.ctxType = MUSIC_AUDIO_OGG;
   1558             music.ctxData = ctxOgg;
   1559             stb_vorbis_info info = stb_vorbis_get_info((stb_vorbis *)music.ctxData);  // Get Ogg file info
   1560 
   1561             // OGG bit rate defaults to 16 bit, it's enough for compressed format
   1562             music.stream = LoadAudioStream(info.sample_rate, 16, info.channels);
   1563 
   1564             // WARNING: It seems this function returns length in frames, not samples, so we multiply by channels
   1565             music.frameCount = (unsigned int)stb_vorbis_stream_length_in_samples((stb_vorbis *)music.ctxData);
   1566             music.looping = true;   // Looping enabled by default
   1567             musicLoaded = true;
   1568         }
   1569         else
   1570         {
   1571             stb_vorbis_close(ctxOgg);
   1572         }
   1573     }
   1574 #endif
   1575 #if defined(SUPPORT_FILEFORMAT_MP3)
   1576     else if ((strcmp(fileType, ".mp3") == 0) || (strcmp(fileType, ".MP3") == 0))
   1577     {
   1578         drmp3 *ctxMp3 = RL_CALLOC(1, sizeof(drmp3));
   1579         int success = drmp3_init_memory(ctxMp3, (const void*)data, dataSize, NULL);
   1580 
   1581         if (success)
   1582         {
   1583             music.ctxType = MUSIC_AUDIO_MP3;
   1584             music.ctxData = ctxMp3;
   1585             music.stream = LoadAudioStream(ctxMp3->sampleRate, 32, ctxMp3->channels);
   1586             music.frameCount = (unsigned int)drmp3_get_pcm_frame_count(ctxMp3);
   1587             music.looping = true;   // Looping enabled by default
   1588             musicLoaded = true;
   1589         }
   1590         else
   1591         {
   1592             drmp3_uninit(ctxMp3);
   1593             RL_FREE(ctxMp3);
   1594         }
   1595     }
   1596 #endif
   1597 #if defined(SUPPORT_FILEFORMAT_QOA)
   1598     else if ((strcmp(fileType, ".qoa") == 0) || (strcmp(fileType, ".QOA") == 0))
   1599     {
   1600         qoaplay_desc *ctxQoa = NULL;
   1601         if ((data != NULL) && (dataSize > 0))
   1602         {
   1603             ctxQoa = qoaplay_open_memory(data, dataSize);
   1604         }
   1605 
   1606         if (ctxQoa != NULL)
   1607         {
   1608             music.ctxType = MUSIC_AUDIO_QOA;
   1609             music.ctxData = ctxQoa;
   1610             // NOTE: We are loading samples are 32bit float normalized data, so,
   1611             // we configure the output audio stream to also use float 32bit
   1612             music.stream = LoadAudioStream(ctxQoa->info.samplerate, 32, ctxQoa->info.channels);
   1613             music.frameCount = ctxQoa->info.samples;
   1614             music.looping = true;   // Looping enabled by default
   1615             musicLoaded = true;
   1616         }
   1617         else{} //No uninit required
   1618     }
   1619 #endif
   1620 #if defined(SUPPORT_FILEFORMAT_FLAC)
   1621     else if ((strcmp(fileType, ".flac") == 0) || (strcmp(fileType, ".FLAC") == 0))
   1622     {
   1623         drflac *ctxFlac = drflac_open_memory((const void*)data, dataSize, NULL);
   1624 
   1625         if (ctxFlac != NULL)
   1626         {
   1627             music.ctxType = MUSIC_AUDIO_FLAC;
   1628             music.ctxData = ctxFlac;
   1629             int sampleSize = ctxFlac->bitsPerSample;
   1630             if (ctxFlac->bitsPerSample == 24) sampleSize = 16;   // Forcing conversion to s16 on UpdateMusicStream()
   1631             music.stream = LoadAudioStream(ctxFlac->sampleRate, sampleSize, ctxFlac->channels);
   1632             music.frameCount = (unsigned int)ctxFlac->totalPCMFrameCount;
   1633             music.looping = true;   // Looping enabled by default
   1634             musicLoaded = true;
   1635         }
   1636         else
   1637         {
   1638             drflac_free(ctxFlac, NULL);
   1639         }
   1640     }
   1641 #endif
   1642 #if defined(SUPPORT_FILEFORMAT_XM)
   1643     else if ((strcmp(fileType, ".xm") == 0) || (strcmp(fileType, ".XM") == 0))
   1644     {
   1645         jar_xm_context_t *ctxXm = NULL;
   1646         int result = jar_xm_create_context_safe(&ctxXm, (const char *)data, dataSize, AUDIO.System.device.sampleRate);
   1647         if (result == 0)    // XM AUDIO.System.context created successfully
   1648         {
   1649             music.ctxType = MUSIC_MODULE_XM;
   1650             music.ctxData = ctxXm;
   1651             jar_xm_set_max_loop_count(ctxXm, 0);    // Set infinite number of loops
   1652 
   1653             unsigned int bits = 32;
   1654             if (AUDIO_DEVICE_FORMAT == ma_format_s16) bits = 16;
   1655             else if (AUDIO_DEVICE_FORMAT == ma_format_u8) bits = 8;
   1656 
   1657             // NOTE: Only stereo is supported for XM
   1658             music.stream = LoadAudioStream(AUDIO.System.device.sampleRate, bits, 2);
   1659             music.frameCount = (unsigned int)jar_xm_get_remaining_samples(ctxXm);    // NOTE: Always 2 channels (stereo)
   1660             music.looping = true;   // Looping enabled by default
   1661             jar_xm_reset(ctxXm);    // Make sure we start at the beginning of the song
   1662 
   1663             musicLoaded = true;
   1664         }
   1665         else
   1666         {
   1667             jar_xm_free_context(ctxXm);
   1668         }
   1669     }
   1670 #endif
   1671 #if defined(SUPPORT_FILEFORMAT_MOD)
   1672     else if ((strcmp(fileType, ".mod") == 0) || (strcmp(fileType, ".MOD") == 0))
   1673     {
   1674         jar_mod_context_t *ctxMod = (jar_mod_context_t *)RL_MALLOC(sizeof(jar_mod_context_t));
   1675         int result = 0;
   1676 
   1677         jar_mod_init(ctxMod);
   1678 
   1679         // Copy data to allocated memory for default UnloadMusicStream
   1680         unsigned char *newData = (unsigned char *)RL_MALLOC(dataSize);
   1681         int it = dataSize/sizeof(unsigned char);
   1682         for (int i = 0; i < it; i++) newData[i] = data[i];
   1683 
   1684         // Memory loaded version for jar_mod_load_file()
   1685         if (dataSize && (dataSize < 32*1024*1024))
   1686         {
   1687             ctxMod->modfilesize = dataSize;
   1688             ctxMod->modfile = newData;
   1689             if (jar_mod_load(ctxMod, (void *)ctxMod->modfile, dataSize)) result = dataSize;
   1690         }
   1691 
   1692         if (result > 0)
   1693         {
   1694             music.ctxType = MUSIC_MODULE_MOD;
   1695             music.ctxData = ctxMod;
   1696 
   1697             // NOTE: Only stereo is supported for MOD
   1698             music.stream = LoadAudioStream(AUDIO.System.device.sampleRate, 16, 2);
   1699             music.frameCount = (unsigned int)jar_mod_max_samples(ctxMod);    // NOTE: Always 2 channels (stereo)
   1700             music.looping = true;   // Looping enabled by default
   1701             musicLoaded = true;
   1702         }
   1703         else
   1704         {
   1705             jar_mod_unload(ctxMod);
   1706             RL_FREE(ctxMod);
   1707         }
   1708     }
   1709 #endif
   1710     else TRACELOG(LOG_WARNING, "STREAM: Data format not supported");
   1711 
   1712     if (!musicLoaded)
   1713     {
   1714         TRACELOG(LOG_WARNING, "FILEIO: Music data could not be loaded");
   1715     }
   1716     else
   1717     {
   1718         // Show some music stream info
   1719         TRACELOG(LOG_INFO, "FILEIO: Music data loaded successfully");
   1720         TRACELOG(LOG_INFO, "    > Sample rate:   %i Hz", music.stream.sampleRate);
   1721         TRACELOG(LOG_INFO, "    > Sample size:   %i bits", music.stream.sampleSize);
   1722         TRACELOG(LOG_INFO, "    > Channels:      %i (%s)", music.stream.channels, (music.stream.channels == 1)? "Mono" : (music.stream.channels == 2)? "Stereo" : "Multi");
   1723         TRACELOG(LOG_INFO, "    > Total frames:  %i", music.frameCount);
   1724     }
   1725 
   1726     return music;
   1727 }
   1728 
   1729 // Checks if a music stream is valid (context and buffers initialized)
   1730 bool IsMusicValid(Music music)
   1731 {
   1732     return ((music.ctxData != NULL) &&          // Validate context loaded
   1733             (music.frameCount > 0) &&           // Validate audio frame count
   1734             (music.stream.sampleRate > 0) &&    // Validate sample rate is supported
   1735             (music.stream.sampleSize > 0) &&    // Validate sample size is supported
   1736             (music.stream.channels > 0));       // Validate number of channels supported
   1737 }
   1738 
   1739 // Unload music stream
   1740 void UnloadMusicStream(Music music)
   1741 {
   1742     UnloadAudioStream(music.stream);
   1743 
   1744     if (music.ctxData != NULL)
   1745     {
   1746         if (false) { }
   1747 #if defined(SUPPORT_FILEFORMAT_WAV)
   1748         else if (music.ctxType == MUSIC_AUDIO_WAV) drwav_uninit((drwav *)music.ctxData);
   1749 #endif
   1750 #if defined(SUPPORT_FILEFORMAT_OGG)
   1751         else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
   1752 #endif
   1753 #if defined(SUPPORT_FILEFORMAT_MP3)
   1754         else if (music.ctxType == MUSIC_AUDIO_MP3) { drmp3_uninit((drmp3 *)music.ctxData); RL_FREE(music.ctxData); }
   1755 #endif
   1756 #if defined(SUPPORT_FILEFORMAT_QOA)
   1757         else if (music.ctxType == MUSIC_AUDIO_QOA) qoaplay_close((qoaplay_desc *)music.ctxData);
   1758 #endif
   1759 #if defined(SUPPORT_FILEFORMAT_FLAC)
   1760         else if (music.ctxType == MUSIC_AUDIO_FLAC) drflac_free((drflac *)music.ctxData, NULL);
   1761 #endif
   1762 #if defined(SUPPORT_FILEFORMAT_XM)
   1763         else if (music.ctxType == MUSIC_MODULE_XM) jar_xm_free_context((jar_xm_context_t *)music.ctxData);
   1764 #endif
   1765 #if defined(SUPPORT_FILEFORMAT_MOD)
   1766         else if (music.ctxType == MUSIC_MODULE_MOD) { jar_mod_unload((jar_mod_context_t *)music.ctxData); RL_FREE(music.ctxData); }
   1767 #endif
   1768     }
   1769 }
   1770 
   1771 // Start music playing (open stream) from beginning
   1772 void PlayMusicStream(Music music)
   1773 {
   1774     PlayAudioStream(music.stream);
   1775 }
   1776 
   1777 // Pause music playing
   1778 void PauseMusicStream(Music music)
   1779 {
   1780     PauseAudioStream(music.stream);
   1781 }
   1782 
   1783 // Resume music playing
   1784 void ResumeMusicStream(Music music)
   1785 {
   1786     ResumeAudioStream(music.stream);
   1787 }
   1788 
   1789 // Stop music playing (close stream)
   1790 void StopMusicStream(Music music)
   1791 {
   1792     StopAudioStream(music.stream);
   1793 
   1794     switch (music.ctxType)
   1795     {
   1796 #if defined(SUPPORT_FILEFORMAT_WAV)
   1797         case MUSIC_AUDIO_WAV: drwav_seek_to_first_pcm_frame((drwav *)music.ctxData); break;
   1798 #endif
   1799 #if defined(SUPPORT_FILEFORMAT_OGG)
   1800         case MUSIC_AUDIO_OGG: stb_vorbis_seek_start((stb_vorbis *)music.ctxData); break;
   1801 #endif
   1802 #if defined(SUPPORT_FILEFORMAT_MP3)
   1803         case MUSIC_AUDIO_MP3: drmp3_seek_to_start_of_stream((drmp3 *)music.ctxData); break;
   1804 #endif
   1805 #if defined(SUPPORT_FILEFORMAT_QOA)
   1806         case MUSIC_AUDIO_QOA: qoaplay_rewind((qoaplay_desc *)music.ctxData); break;
   1807 #endif
   1808 #if defined(SUPPORT_FILEFORMAT_FLAC)
   1809         case MUSIC_AUDIO_FLAC: drflac__seek_to_first_frame((drflac *)music.ctxData); break;
   1810 #endif
   1811 #if defined(SUPPORT_FILEFORMAT_XM)
   1812         case MUSIC_MODULE_XM: jar_xm_reset((jar_xm_context_t *)music.ctxData); break;
   1813 #endif
   1814 #if defined(SUPPORT_FILEFORMAT_MOD)
   1815         case MUSIC_MODULE_MOD: jar_mod_seek_start((jar_mod_context_t *)music.ctxData); break;
   1816 #endif
   1817         default: break;
   1818     }
   1819 }
   1820 
   1821 // Seek music to a certain position (in seconds)
   1822 void SeekMusicStream(Music music, float position)
   1823 {
   1824     // Seeking is not supported in module formats
   1825     if ((music.ctxType == MUSIC_MODULE_XM) || (music.ctxType == MUSIC_MODULE_MOD)) return;
   1826 
   1827     unsigned int positionInFrames = (unsigned int)(position*music.stream.sampleRate);
   1828 
   1829     switch (music.ctxType)
   1830     {
   1831 #if defined(SUPPORT_FILEFORMAT_WAV)
   1832         case MUSIC_AUDIO_WAV: drwav_seek_to_pcm_frame((drwav *)music.ctxData, positionInFrames); break;
   1833 #endif
   1834 #if defined(SUPPORT_FILEFORMAT_OGG)
   1835         case MUSIC_AUDIO_OGG: stb_vorbis_seek_frame((stb_vorbis *)music.ctxData, positionInFrames); break;
   1836 #endif
   1837 #if defined(SUPPORT_FILEFORMAT_MP3)
   1838         case MUSIC_AUDIO_MP3: drmp3_seek_to_pcm_frame((drmp3 *)music.ctxData, positionInFrames); break;
   1839 #endif
   1840 #if defined(SUPPORT_FILEFORMAT_QOA)
   1841         case MUSIC_AUDIO_QOA:
   1842         {
   1843             int qoaFrame = positionInFrames/QOA_FRAME_LEN;
   1844             qoaplay_seek_frame((qoaplay_desc *)music.ctxData, qoaFrame); // Seeks to QOA frame, not PCM frame
   1845 
   1846             // We need to compute QOA frame number and update positionInFrames
   1847             positionInFrames = ((qoaplay_desc *)music.ctxData)->sample_position;
   1848         } break;
   1849 #endif
   1850 #if defined(SUPPORT_FILEFORMAT_FLAC)
   1851         case MUSIC_AUDIO_FLAC: drflac_seek_to_pcm_frame((drflac *)music.ctxData, positionInFrames); break;
   1852 #endif
   1853         default: break;
   1854     }
   1855 
   1856     ma_mutex_lock(&AUDIO.System.lock);
   1857     music.stream.buffer->framesProcessed = positionInFrames;
   1858     ma_mutex_unlock(&AUDIO.System.lock);
   1859 }
   1860 
   1861 // Update (re-fill) music buffers if data already processed
   1862 void UpdateMusicStream(Music music)
   1863 {
   1864     if (music.stream.buffer == NULL) return;
   1865 
   1866     ma_mutex_lock(&AUDIO.System.lock);
   1867 
   1868     unsigned int subBufferSizeInFrames = music.stream.buffer->sizeInFrames/2;
   1869 
   1870     // On first call of this function we lazily pre-allocated a temp buffer to read audio files/memory data in
   1871     int frameSize = music.stream.channels*music.stream.sampleSize/8;
   1872     unsigned int pcmSize = subBufferSizeInFrames*frameSize;
   1873 
   1874     if (AUDIO.System.pcmBufferSize < pcmSize)
   1875     {
   1876         RL_FREE(AUDIO.System.pcmBuffer);
   1877         AUDIO.System.pcmBuffer = RL_CALLOC(1, pcmSize);
   1878         AUDIO.System.pcmBufferSize = pcmSize;
   1879     }
   1880 
   1881     // Check both sub-buffers to check if they require refilling
   1882     for (int i = 0; i < 2; i++)
   1883     {
   1884         if (!music.stream.buffer->isSubBufferProcessed[i]) continue; // No refilling required, move to next sub-buffer
   1885 
   1886         unsigned int framesLeft = music.frameCount - music.stream.buffer->framesProcessed;  // Frames left to be processed
   1887         unsigned int framesToStream = 0;                 // Total frames to be streamed
   1888 
   1889         if ((framesLeft >= subBufferSizeInFrames) || music.looping) framesToStream = subBufferSizeInFrames;
   1890         else framesToStream = framesLeft;
   1891 
   1892         int frameCountStillNeeded = framesToStream;
   1893         int frameCountReadTotal = 0;
   1894 
   1895         switch (music.ctxType)
   1896         {
   1897         #if defined(SUPPORT_FILEFORMAT_WAV)
   1898             case MUSIC_AUDIO_WAV:
   1899             {
   1900                 if (music.stream.sampleSize == 16)
   1901                 {
   1902                     while (true)
   1903                     {
   1904                         int frameCountRead = (int)drwav_read_pcm_frames_s16((drwav *)music.ctxData, frameCountStillNeeded, (short *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize));
   1905                         frameCountReadTotal += frameCountRead;
   1906                         frameCountStillNeeded -= frameCountRead;
   1907                         if (frameCountStillNeeded == 0) break;
   1908                         else drwav_seek_to_first_pcm_frame((drwav *)music.ctxData);
   1909                     }
   1910                 }
   1911                 else if (music.stream.sampleSize == 32)
   1912                 {
   1913                     while (true)
   1914                     {
   1915                         int frameCountRead = (int)drwav_read_pcm_frames_f32((drwav *)music.ctxData, frameCountStillNeeded, (float *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize));
   1916                         frameCountReadTotal += frameCountRead;
   1917                         frameCountStillNeeded -= frameCountRead;
   1918                         if (frameCountStillNeeded == 0) break;
   1919                         else drwav_seek_to_first_pcm_frame((drwav *)music.ctxData);
   1920                     }
   1921                 }
   1922             } break;
   1923         #endif
   1924         #if defined(SUPPORT_FILEFORMAT_OGG)
   1925             case MUSIC_AUDIO_OGG:
   1926             {
   1927                 while (true)
   1928                 {
   1929                     int frameCountRead = stb_vorbis_get_samples_short_interleaved((stb_vorbis *)music.ctxData, music.stream.channels, (short *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize), frameCountStillNeeded*music.stream.channels);
   1930                     frameCountReadTotal += frameCountRead;
   1931                     frameCountStillNeeded -= frameCountRead;
   1932                     if (frameCountStillNeeded == 0) break;
   1933                     else stb_vorbis_seek_start((stb_vorbis *)music.ctxData);
   1934                 }
   1935             } break;
   1936         #endif
   1937         #if defined(SUPPORT_FILEFORMAT_MP3)
   1938             case MUSIC_AUDIO_MP3:
   1939             {
   1940                 while (true)
   1941                 {
   1942                     int frameCountRead = (int)drmp3_read_pcm_frames_f32((drmp3 *)music.ctxData, frameCountStillNeeded, (float *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize));
   1943                     frameCountReadTotal += frameCountRead;
   1944                     frameCountStillNeeded -= frameCountRead;
   1945                     if (frameCountStillNeeded == 0) break;
   1946                     else drmp3_seek_to_start_of_stream((drmp3 *)music.ctxData);
   1947                 }
   1948             } break;
   1949         #endif
   1950         #if defined(SUPPORT_FILEFORMAT_QOA)
   1951             case MUSIC_AUDIO_QOA:
   1952             {
   1953                 unsigned int frameCountRead = qoaplay_decode((qoaplay_desc *)music.ctxData, (float *)AUDIO.System.pcmBuffer, framesToStream);
   1954                 frameCountReadTotal += frameCountRead;
   1955                 /*
   1956                 while (true)
   1957                 {
   1958                     int frameCountRead = (int)qoaplay_decode((qoaplay_desc *)music.ctxData, (float *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize),  frameCountStillNeeded);
   1959                     frameCountReadTotal += frameCountRead;
   1960                     frameCountStillNeeded -= frameCountRead;
   1961                     if (frameCountStillNeeded == 0) break;
   1962                     else qoaplay_rewind((qoaplay_desc *)music.ctxData);
   1963                 }
   1964                 */
   1965             } break;
   1966         #endif
   1967         #if defined(SUPPORT_FILEFORMAT_FLAC)
   1968             case MUSIC_AUDIO_FLAC:
   1969             {
   1970                 while (true)
   1971                 {
   1972                     int frameCountRead = (int)drflac_read_pcm_frames_s16((drflac *)music.ctxData, frameCountStillNeeded, (short *)((char *)AUDIO.System.pcmBuffer + frameCountReadTotal*frameSize));
   1973                     frameCountReadTotal += frameCountRead;
   1974                     frameCountStillNeeded -= frameCountRead;
   1975                     if (frameCountStillNeeded == 0) break;
   1976                     else drflac__seek_to_first_frame((drflac *)music.ctxData);
   1977                 }
   1978             } break;
   1979         #endif
   1980         #if defined(SUPPORT_FILEFORMAT_XM)
   1981             case MUSIC_MODULE_XM:
   1982             {
   1983                 // NOTE: Internally we consider 2 channels generation, so sampleCount/2
   1984                 if (AUDIO_DEVICE_FORMAT == ma_format_f32) jar_xm_generate_samples((jar_xm_context_t *)music.ctxData, (float *)AUDIO.System.pcmBuffer, framesToStream);
   1985                 else if (AUDIO_DEVICE_FORMAT == ma_format_s16) jar_xm_generate_samples_16bit((jar_xm_context_t *)music.ctxData, (short *)AUDIO.System.pcmBuffer, framesToStream);
   1986                 else if (AUDIO_DEVICE_FORMAT == ma_format_u8) jar_xm_generate_samples_8bit((jar_xm_context_t *)music.ctxData, (char *)AUDIO.System.pcmBuffer, framesToStream);
   1987                 //jar_xm_reset((jar_xm_context_t *)music.ctxData);
   1988 
   1989             } break;
   1990         #endif
   1991         #if defined(SUPPORT_FILEFORMAT_MOD)
   1992             case MUSIC_MODULE_MOD:
   1993             {
   1994                 // NOTE: 3rd parameter (nbsample) specify the number of stereo 16bits samples you want, so sampleCount/2
   1995                 jar_mod_fillbuffer((jar_mod_context_t *)music.ctxData, (short *)AUDIO.System.pcmBuffer, framesToStream, 0);
   1996                 //jar_mod_seek_start((jar_mod_context_t *)music.ctxData);
   1997 
   1998             } break;
   1999         #endif
   2000             default: break;
   2001         }
   2002 
   2003         UpdateAudioStreamInLockedState(music.stream, AUDIO.System.pcmBuffer, framesToStream);
   2004 
   2005         music.stream.buffer->framesProcessed = music.stream.buffer->framesProcessed%music.frameCount;
   2006 
   2007         if (framesLeft <= subBufferSizeInFrames)
   2008         {
   2009             if (!music.looping)
   2010             {
   2011                 ma_mutex_unlock(&AUDIO.System.lock);
   2012                 // Streaming is ending, we filled latest frames from input
   2013                 StopMusicStream(music);
   2014                 return;
   2015             }
   2016         }
   2017     }
   2018 
   2019     ma_mutex_unlock(&AUDIO.System.lock);
   2020 }
   2021 
   2022 // Check if any music is playing
   2023 bool IsMusicStreamPlaying(Music music)
   2024 {
   2025     return IsAudioStreamPlaying(music.stream);
   2026 }
   2027 
   2028 // Set volume for music
   2029 void SetMusicVolume(Music music, float volume)
   2030 {
   2031     SetAudioStreamVolume(music.stream, volume);
   2032 }
   2033 
   2034 // Set pitch for music
   2035 void SetMusicPitch(Music music, float pitch)
   2036 {
   2037     SetAudioBufferPitch(music.stream.buffer, pitch);
   2038 }
   2039 
   2040 // Set pan for a music
   2041 void SetMusicPan(Music music, float pan)
   2042 {
   2043     SetAudioBufferPan(music.stream.buffer, pan);
   2044 }
   2045 
   2046 // Get music time length (in seconds)
   2047 float GetMusicTimeLength(Music music)
   2048 {
   2049     float totalSeconds = 0.0f;
   2050 
   2051     totalSeconds = (float)music.frameCount/music.stream.sampleRate;
   2052 
   2053     return totalSeconds;
   2054 }
   2055 
   2056 // Get current music time played (in seconds)
   2057 float GetMusicTimePlayed(Music music)
   2058 {
   2059     float secondsPlayed = 0.0f;
   2060     if (music.stream.buffer != NULL)
   2061     {
   2062 #if defined(SUPPORT_FILEFORMAT_XM)
   2063         if (music.ctxType == MUSIC_MODULE_XM)
   2064         {
   2065             uint64_t framesPlayed = 0;
   2066 
   2067             jar_xm_get_position(music.ctxData, NULL, NULL, NULL, &framesPlayed);
   2068             secondsPlayed = (float)framesPlayed/music.stream.sampleRate;
   2069         }
   2070         else
   2071 #endif
   2072         {
   2073             ma_mutex_lock(&AUDIO.System.lock);
   2074             //ma_uint32 frameSizeInBytes = ma_get_bytes_per_sample(music.stream.buffer->dsp.formatConverterIn.config.formatIn)*music.stream.buffer->dsp.formatConverterIn.config.channels;
   2075             int framesProcessed = (int)music.stream.buffer->framesProcessed;
   2076             int subBufferSize = (int)music.stream.buffer->sizeInFrames/2;
   2077             int framesInFirstBuffer = music.stream.buffer->isSubBufferProcessed[0]? 0 : subBufferSize;
   2078             int framesInSecondBuffer = music.stream.buffer->isSubBufferProcessed[1]? 0 : subBufferSize;
   2079             int framesSentToMix = music.stream.buffer->frameCursorPos%subBufferSize;
   2080             int framesPlayed = (framesProcessed - framesInFirstBuffer - framesInSecondBuffer + framesSentToMix)%(int)music.frameCount;
   2081             if (framesPlayed < 0) framesPlayed += music.frameCount;
   2082             secondsPlayed = (float)framesPlayed/music.stream.sampleRate;
   2083             ma_mutex_unlock(&AUDIO.System.lock);
   2084         }
   2085     }
   2086 
   2087     return secondsPlayed;
   2088 }
   2089 
   2090 // Load audio stream (to stream audio pcm data)
   2091 AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels)
   2092 {
   2093     AudioStream stream = { 0 };
   2094 
   2095     stream.sampleRate = sampleRate;
   2096     stream.sampleSize = sampleSize;
   2097     stream.channels = channels;
   2098 
   2099     ma_format formatIn = ((stream.sampleSize == 8)? ma_format_u8 : ((stream.sampleSize == 16)? ma_format_s16 : ma_format_f32));
   2100 
   2101     // The size of a streaming buffer must be at least double the size of a period
   2102     unsigned int periodSize = AUDIO.System.device.playback.internalPeriodSizeInFrames;
   2103 
   2104     // If the buffer is not set, compute one that would give us a buffer good enough for a decent frame rate
   2105     unsigned int subBufferSize = (AUDIO.Buffer.defaultSize == 0)? AUDIO.System.device.sampleRate/30 : AUDIO.Buffer.defaultSize;
   2106 
   2107     if (subBufferSize < periodSize) subBufferSize = periodSize;
   2108 
   2109     // Create a double audio buffer of defined size
   2110     stream.buffer = LoadAudioBuffer(formatIn, stream.channels, stream.sampleRate, subBufferSize*2, AUDIO_BUFFER_USAGE_STREAM);
   2111 
   2112     if (stream.buffer != NULL)
   2113     {
   2114         stream.buffer->looping = true;    // Always loop for streaming buffers
   2115         TRACELOG(LOG_INFO, "STREAM: Initialized successfully (%i Hz, %i bit, %s)", stream.sampleRate, stream.sampleSize, (stream.channels == 1)? "Mono" : "Stereo");
   2116     }
   2117     else TRACELOG(LOG_WARNING, "STREAM: Failed to load audio buffer, stream could not be created");
   2118 
   2119     return stream;
   2120 }
   2121 
   2122 // Checks if an audio stream is valid (buffers initialized)
   2123 bool IsAudioStreamValid(AudioStream stream)
   2124 {
   2125     return ((stream.buffer != NULL) &&    // Validate stream buffer
   2126             (stream.sampleRate > 0) &&    // Validate sample rate is supported
   2127             (stream.sampleSize > 0) &&    // Validate sample size is supported
   2128             (stream.channels > 0));       // Validate number of channels supported
   2129 }
   2130 
   2131 // Unload audio stream and free memory
   2132 void UnloadAudioStream(AudioStream stream)
   2133 {
   2134     UnloadAudioBuffer(stream.buffer);
   2135 
   2136     TRACELOG(LOG_INFO, "STREAM: Unloaded audio stream data from RAM");
   2137 }
   2138 
   2139 // Update audio stream buffers with data
   2140 // NOTE 1: Only updates one buffer of the stream source: dequeue -> update -> queue
   2141 // NOTE 2: To dequeue a buffer it needs to be processed: IsAudioStreamProcessed()
   2142 void UpdateAudioStream(AudioStream stream, const void *data, int frameCount)
   2143 {
   2144     ma_mutex_lock(&AUDIO.System.lock);
   2145     UpdateAudioStreamInLockedState(stream, data, frameCount);
   2146     ma_mutex_unlock(&AUDIO.System.lock);
   2147 }
   2148 
   2149 // Check if any audio stream buffers requires refill
   2150 bool IsAudioStreamProcessed(AudioStream stream)
   2151 {
   2152     if (stream.buffer == NULL) return false;
   2153 
   2154     bool result = false;
   2155     ma_mutex_lock(&AUDIO.System.lock);
   2156     result = stream.buffer->isSubBufferProcessed[0] || stream.buffer->isSubBufferProcessed[1];
   2157     ma_mutex_unlock(&AUDIO.System.lock);
   2158     return result;
   2159 }
   2160 
   2161 // Play audio stream
   2162 void PlayAudioStream(AudioStream stream)
   2163 {
   2164     PlayAudioBuffer(stream.buffer);
   2165 }
   2166 
   2167 // Play audio stream
   2168 void PauseAudioStream(AudioStream stream)
   2169 {
   2170     PauseAudioBuffer(stream.buffer);
   2171 }
   2172 
   2173 // Resume audio stream playing
   2174 void ResumeAudioStream(AudioStream stream)
   2175 {
   2176     ResumeAudioBuffer(stream.buffer);
   2177 }
   2178 
   2179 // Check if audio stream is playing
   2180 bool IsAudioStreamPlaying(AudioStream stream)
   2181 {
   2182     return IsAudioBufferPlaying(stream.buffer);
   2183 }
   2184 
   2185 // Stop audio stream
   2186 void StopAudioStream(AudioStream stream)
   2187 {
   2188     StopAudioBuffer(stream.buffer);
   2189 }
   2190 
   2191 // Set volume for audio stream (1.0 is max level)
   2192 void SetAudioStreamVolume(AudioStream stream, float volume)
   2193 {
   2194     SetAudioBufferVolume(stream.buffer, volume);
   2195 }
   2196 
   2197 // Set pitch for audio stream (1.0 is base level)
   2198 void SetAudioStreamPitch(AudioStream stream, float pitch)
   2199 {
   2200     SetAudioBufferPitch(stream.buffer, pitch);
   2201 }
   2202 
   2203 // Set pan for audio stream
   2204 void SetAudioStreamPan(AudioStream stream, float pan)
   2205 {
   2206     SetAudioBufferPan(stream.buffer, pan);
   2207 }
   2208 
   2209 // Default size for new audio streams
   2210 void SetAudioStreamBufferSizeDefault(int size)
   2211 {
   2212     AUDIO.Buffer.defaultSize = size;
   2213 }
   2214 
   2215 // Audio thread callback to request new data
   2216 void SetAudioStreamCallback(AudioStream stream, AudioCallback callback)
   2217 {
   2218     if (stream.buffer != NULL)
   2219     {
   2220         ma_mutex_lock(&AUDIO.System.lock);
   2221         stream.buffer->callback = callback;
   2222         ma_mutex_unlock(&AUDIO.System.lock);
   2223     }
   2224 }
   2225 
   2226 // Add processor to audio stream. Contrary to buffers, the order of processors is important
   2227 // The new processor must be added at the end. As there aren't supposed to be a lot of processors attached to
   2228 // a given stream, we iterate through the list to find the end. That way we don't need a pointer to the last element
   2229 void AttachAudioStreamProcessor(AudioStream stream, AudioCallback process)
   2230 {
   2231     ma_mutex_lock(&AUDIO.System.lock);
   2232 
   2233     rAudioProcessor *processor = (rAudioProcessor *)RL_CALLOC(1, sizeof(rAudioProcessor));
   2234     processor->process = process;
   2235 
   2236     rAudioProcessor *last = stream.buffer->processor;
   2237 
   2238     while (last && last->next)
   2239     {
   2240         last = last->next;
   2241     }
   2242     if (last)
   2243     {
   2244         processor->prev = last;
   2245         last->next = processor;
   2246     }
   2247     else stream.buffer->processor = processor;
   2248 
   2249     ma_mutex_unlock(&AUDIO.System.lock);
   2250 }
   2251 
   2252 // Remove processor from audio stream
   2253 void DetachAudioStreamProcessor(AudioStream stream, AudioCallback process)
   2254 {
   2255     ma_mutex_lock(&AUDIO.System.lock);
   2256 
   2257     rAudioProcessor *processor = stream.buffer->processor;
   2258 
   2259     while (processor)
   2260     {
   2261         rAudioProcessor *next = processor->next;
   2262         rAudioProcessor *prev = processor->prev;
   2263 
   2264         if (processor->process == process)
   2265         {
   2266             if (stream.buffer->processor == processor) stream.buffer->processor = next;
   2267             if (prev) prev->next = next;
   2268             if (next) next->prev = prev;
   2269 
   2270             RL_FREE(processor);
   2271         }
   2272 
   2273         processor = next;
   2274     }
   2275 
   2276     ma_mutex_unlock(&AUDIO.System.lock);
   2277 }
   2278 
   2279 // Add processor to audio pipeline. Order of processors is important
   2280 // Works the same way as {Attach,Detach}AudioStreamProcessor() functions, except
   2281 // these two work on the already mixed output just before sending it to the sound hardware
   2282 void AttachAudioMixedProcessor(AudioCallback process)
   2283 {
   2284     ma_mutex_lock(&AUDIO.System.lock);
   2285 
   2286     rAudioProcessor *processor = (rAudioProcessor *)RL_CALLOC(1, sizeof(rAudioProcessor));
   2287     processor->process = process;
   2288 
   2289     rAudioProcessor *last = AUDIO.mixedProcessor;
   2290 
   2291     while (last && last->next)
   2292     {
   2293         last = last->next;
   2294     }
   2295     if (last)
   2296     {
   2297         processor->prev = last;
   2298         last->next = processor;
   2299     }
   2300     else AUDIO.mixedProcessor = processor;
   2301 
   2302     ma_mutex_unlock(&AUDIO.System.lock);
   2303 }
   2304 
   2305 // Remove processor from audio pipeline
   2306 void DetachAudioMixedProcessor(AudioCallback process)
   2307 {
   2308     ma_mutex_lock(&AUDIO.System.lock);
   2309 
   2310     rAudioProcessor *processor = AUDIO.mixedProcessor;
   2311 
   2312     while (processor)
   2313     {
   2314         rAudioProcessor *next = processor->next;
   2315         rAudioProcessor *prev = processor->prev;
   2316 
   2317         if (processor->process == process)
   2318         {
   2319             if (AUDIO.mixedProcessor == processor) AUDIO.mixedProcessor = next;
   2320             if (prev) prev->next = next;
   2321             if (next) next->prev = prev;
   2322 
   2323             RL_FREE(processor);
   2324         }
   2325 
   2326         processor = next;
   2327     }
   2328 
   2329     ma_mutex_unlock(&AUDIO.System.lock);
   2330 }
   2331 
   2332 
   2333 //----------------------------------------------------------------------------------
   2334 // Module specific Functions Definition
   2335 //----------------------------------------------------------------------------------
   2336 
   2337 // Log callback function
   2338 static void OnLog(void *pUserData, ma_uint32 level, const char *pMessage)
   2339 {
   2340     TRACELOG(LOG_WARNING, "miniaudio: %s", pMessage);   // All log messages from miniaudio are errors
   2341 }
   2342 
   2343 // Reads audio data from an AudioBuffer object in internal format
   2344 static ma_uint32 ReadAudioBufferFramesInInternalFormat(AudioBuffer *audioBuffer, void *framesOut, ma_uint32 frameCount)
   2345 {
   2346     // Using audio buffer callback
   2347     if (audioBuffer->callback)
   2348     {
   2349         audioBuffer->callback(framesOut, frameCount);
   2350         audioBuffer->framesProcessed += frameCount;
   2351 
   2352         return frameCount;
   2353     }
   2354 
   2355     ma_uint32 subBufferSizeInFrames = (audioBuffer->sizeInFrames > 1)? audioBuffer->sizeInFrames/2 : audioBuffer->sizeInFrames;
   2356     ma_uint32 currentSubBufferIndex = audioBuffer->frameCursorPos/subBufferSizeInFrames;
   2357 
   2358     if (currentSubBufferIndex > 1) return 0;
   2359 
   2360     // Another thread can update the processed state of buffers, so
   2361     // we just take a copy here to try and avoid potential synchronization problems
   2362     bool isSubBufferProcessed[2] = { 0 };
   2363     isSubBufferProcessed[0] = audioBuffer->isSubBufferProcessed[0];
   2364     isSubBufferProcessed[1] = audioBuffer->isSubBufferProcessed[1];
   2365 
   2366     ma_uint32 frameSizeInBytes = ma_get_bytes_per_frame(audioBuffer->converter.formatIn, audioBuffer->converter.channelsIn);
   2367 
   2368     // Fill out every frame until we find a buffer that's marked as processed. Then fill the remainder with 0
   2369     ma_uint32 framesRead = 0;
   2370     while (1)
   2371     {
   2372         // We break from this loop differently depending on the buffer's usage
   2373         //  - For static buffers, we simply fill as much data as we can
   2374         //  - For streaming buffers we only fill half of the buffer that are processed
   2375         //    Unprocessed halves must keep their audio data in-tact
   2376         if (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC)
   2377         {
   2378             if (framesRead >= frameCount) break;
   2379         }
   2380         else
   2381         {
   2382             if (isSubBufferProcessed[currentSubBufferIndex]) break;
   2383         }
   2384 
   2385         ma_uint32 totalFramesRemaining = (frameCount - framesRead);
   2386         if (totalFramesRemaining == 0) break;
   2387 
   2388         ma_uint32 framesRemainingInOutputBuffer;
   2389         if (audioBuffer->usage == AUDIO_BUFFER_USAGE_STATIC)
   2390         {
   2391             framesRemainingInOutputBuffer = audioBuffer->sizeInFrames - audioBuffer->frameCursorPos;
   2392         }
   2393         else
   2394         {
   2395             ma_uint32 firstFrameIndexOfThisSubBuffer = subBufferSizeInFrames*currentSubBufferIndex;
   2396             framesRemainingInOutputBuffer = subBufferSizeInFrames - (audioBuffer->frameCursorPos - firstFrameIndexOfThisSubBuffer);
   2397         }
   2398 
   2399         ma_uint32 framesToRead = totalFramesRemaining;
   2400         if (framesToRead > framesRemainingInOutputBuffer) framesToRead = framesRemainingInOutputBuffer;
   2401 
   2402         memcpy((unsigned char *)framesOut + (framesRead*frameSizeInBytes), audioBuffer->data + (audioBuffer->frameCursorPos*frameSizeInBytes), framesToRead*frameSizeInBytes);
   2403         audioBuffer->frameCursorPos = (audioBuffer->frameCursorPos + framesToRead)%audioBuffer->sizeInFrames;
   2404         framesRead += framesToRead;
   2405 
   2406         // If we've read to the end of the buffer, mark it as processed
   2407         if (framesToRead == framesRemainingInOutputBuffer)
   2408         {
   2409             audioBuffer->isSubBufferProcessed[currentSubBufferIndex] = true;
   2410             isSubBufferProcessed[currentSubBufferIndex] = true;
   2411 
   2412             currentSubBufferIndex = (currentSubBufferIndex + 1)%2;
   2413 
   2414             // We need to break from this loop if we're not looping
   2415             if (!audioBuffer->looping)
   2416             {
   2417                 StopAudioBufferInLockedState(audioBuffer);
   2418                 break;
   2419             }
   2420         }
   2421     }
   2422 
   2423     // Zero-fill excess
   2424     ma_uint32 totalFramesRemaining = (frameCount - framesRead);
   2425     if (totalFramesRemaining > 0)
   2426     {
   2427         memset((unsigned char *)framesOut + (framesRead*frameSizeInBytes), 0, totalFramesRemaining*frameSizeInBytes);
   2428 
   2429         // For static buffers we can fill the remaining frames with silence for safety, but we don't want
   2430         // to report those frames as "read". The reason for this is that the caller uses the return value
   2431         // to know whether a non-looping sound has finished playback
   2432         if (audioBuffer->usage != AUDIO_BUFFER_USAGE_STATIC) framesRead += totalFramesRemaining;
   2433     }
   2434 
   2435     return framesRead;
   2436 }
   2437 
   2438 // Reads audio data from an AudioBuffer object in device format, returned data will be in a format appropriate for mixing
   2439 static ma_uint32 ReadAudioBufferFramesInMixingFormat(AudioBuffer *audioBuffer, float *framesOut, ma_uint32 frameCount)
   2440 {
   2441     // What's going on here is that we're continuously converting data from the AudioBuffer's internal format to the mixing format, which
   2442     // should be defined by the output format of the data converter. We do this until frameCount frames have been output. The important
   2443     // detail to remember here is that we never, ever attempt to read more input data than is required for the specified number of output
   2444     // frames. This can be achieved with ma_data_converter_get_required_input_frame_count()
   2445     ma_uint8 inputBuffer[4096] = { 0 };
   2446     ma_uint32 inputBufferFrameCap = sizeof(inputBuffer)/ma_get_bytes_per_frame(audioBuffer->converter.formatIn, audioBuffer->converter.channelsIn);
   2447 
   2448     ma_uint32 totalOutputFramesProcessed = 0;
   2449     while (totalOutputFramesProcessed < frameCount)
   2450     {
   2451         ma_uint64 outputFramesToProcessThisIteration = frameCount - totalOutputFramesProcessed;
   2452         ma_uint64 inputFramesToProcessThisIteration = 0;
   2453 
   2454         (void)ma_data_converter_get_required_input_frame_count(&audioBuffer->converter, outputFramesToProcessThisIteration, &inputFramesToProcessThisIteration);
   2455         if (inputFramesToProcessThisIteration > inputBufferFrameCap)
   2456         {
   2457             inputFramesToProcessThisIteration = inputBufferFrameCap;
   2458         }
   2459 
   2460         float *runningFramesOut = framesOut + (totalOutputFramesProcessed*audioBuffer->converter.channelsOut);
   2461 
   2462         /* At this point we can convert the data to our mixing format. */
   2463         ma_uint64 inputFramesProcessedThisIteration = ReadAudioBufferFramesInInternalFormat(audioBuffer, inputBuffer, (ma_uint32)inputFramesToProcessThisIteration);    /* Safe cast. */
   2464         ma_uint64 outputFramesProcessedThisIteration = outputFramesToProcessThisIteration;
   2465         ma_data_converter_process_pcm_frames(&audioBuffer->converter, inputBuffer, &inputFramesProcessedThisIteration, runningFramesOut, &outputFramesProcessedThisIteration);
   2466 
   2467         totalOutputFramesProcessed += (ma_uint32)outputFramesProcessedThisIteration; /* Safe cast. */
   2468 
   2469         if (inputFramesProcessedThisIteration < inputFramesToProcessThisIteration)
   2470         {
   2471             break;  /* Ran out of input data. */
   2472         }
   2473 
   2474         /* This should never be hit, but will add it here for safety. Ensures we get out of the loop when no input nor output frames are processed. */
   2475         if (inputFramesProcessedThisIteration == 0 && outputFramesProcessedThisIteration == 0)
   2476         {
   2477             break;
   2478         }
   2479     }
   2480 
   2481     return totalOutputFramesProcessed;
   2482 }
   2483 
   2484 // Sending audio data to device callback function
   2485 // This function will be called when miniaudio needs more data
   2486 // NOTE: All the mixing takes place here
   2487 static void OnSendAudioDataToDevice(ma_device *pDevice, void *pFramesOut, const void *pFramesInput, ma_uint32 frameCount)
   2488 {
   2489     (void)pDevice;
   2490 
   2491     // Mixing is basically just an accumulation, we need to initialize the output buffer to 0
   2492     memset(pFramesOut, 0, frameCount*pDevice->playback.channels*ma_get_bytes_per_sample(pDevice->playback.format));
   2493 
   2494     // Using a mutex here for thread-safety which makes things not real-time
   2495     // This is unlikely to be necessary for this project, but may want to consider how you might want to avoid this
   2496     ma_mutex_lock(&AUDIO.System.lock);
   2497     {
   2498         for (AudioBuffer *audioBuffer = AUDIO.Buffer.first; audioBuffer != NULL; audioBuffer = audioBuffer->next)
   2499         {
   2500             // Ignore stopped or paused sounds
   2501             if (!audioBuffer->playing || audioBuffer->paused) continue;
   2502 
   2503             ma_uint32 framesRead = 0;
   2504 
   2505             while (1)
   2506             {
   2507                 if (framesRead >= frameCount) break;
   2508 
   2509                 // Just read as much data as we can from the stream
   2510                 ma_uint32 framesToRead = (frameCount - framesRead);
   2511 
   2512                 while (framesToRead > 0)
   2513                 {
   2514                     float tempBuffer[1024] = { 0 }; // Frames for stereo
   2515 
   2516                     ma_uint32 framesToReadRightNow = framesToRead;
   2517                     if (framesToReadRightNow > sizeof(tempBuffer)/sizeof(tempBuffer[0])/AUDIO_DEVICE_CHANNELS)
   2518                     {
   2519                         framesToReadRightNow = sizeof(tempBuffer)/sizeof(tempBuffer[0])/AUDIO_DEVICE_CHANNELS;
   2520                     }
   2521 
   2522                     ma_uint32 framesJustRead = ReadAudioBufferFramesInMixingFormat(audioBuffer, tempBuffer, framesToReadRightNow);
   2523                     if (framesJustRead > 0)
   2524                     {
   2525                         float *framesOut = (float *)pFramesOut + (framesRead*AUDIO.System.device.playback.channels);
   2526                         float *framesIn = tempBuffer;
   2527 
   2528                         // Apply processors chain if defined
   2529                         rAudioProcessor *processor = audioBuffer->processor;
   2530                         while (processor)
   2531                         {
   2532                             processor->process(framesIn, framesJustRead);
   2533                             processor = processor->next;
   2534                         }
   2535 
   2536                         MixAudioFrames(framesOut, framesIn, framesJustRead, audioBuffer);
   2537 
   2538                         framesToRead -= framesJustRead;
   2539                         framesRead += framesJustRead;
   2540                     }
   2541 
   2542                     if (!audioBuffer->playing)
   2543                     {
   2544                         framesRead = frameCount;
   2545                         break;
   2546                     }
   2547 
   2548                     // If we weren't able to read all the frames we requested, break
   2549                     if (framesJustRead < framesToReadRightNow)
   2550                     {
   2551                         if (!audioBuffer->looping)
   2552                         {
   2553                             StopAudioBufferInLockedState(audioBuffer);
   2554                             break;
   2555                         }
   2556                         else
   2557                         {
   2558                             // Should never get here, but just for safety,
   2559                             // move the cursor position back to the start and continue the loop
   2560                             audioBuffer->frameCursorPos = 0;
   2561                             continue;
   2562                         }
   2563                     }
   2564                 }
   2565 
   2566                 // If for some reason we weren't able to read every frame we'll need to break from the loop
   2567                 // Not doing this could theoretically put us into an infinite loop
   2568                 if (framesToRead > 0) break;
   2569             }
   2570         }
   2571     }
   2572 
   2573     rAudioProcessor *processor = AUDIO.mixedProcessor;
   2574     while (processor)
   2575     {
   2576         processor->process(pFramesOut, frameCount);
   2577         processor = processor->next;
   2578     }
   2579 
   2580     ma_mutex_unlock(&AUDIO.System.lock);
   2581 }
   2582 
   2583 // Main mixing function, pretty simple in this project, just an accumulation
   2584 // NOTE: framesOut is both an input and an output, it is initially filled with zeros outside of this function
   2585 static void MixAudioFrames(float *framesOut, const float *framesIn, ma_uint32 frameCount, AudioBuffer *buffer)
   2586 {
   2587     const float localVolume = buffer->volume;
   2588     const ma_uint32 channels = AUDIO.System.device.playback.channels;
   2589 
   2590     if (channels == 2)  // We consider panning
   2591     {
   2592         const float left = buffer->pan;
   2593         const float right = 1.0f - left;
   2594 
   2595         // Fast sine approximation in [0..1] for pan law: y = 0.5f*x*(3 - x*x);
   2596         const float levels[2] = { localVolume*0.5f*left*(3.0f - left*left), localVolume*0.5f*right*(3.0f - right*right) };
   2597 
   2598         float *frameOut = framesOut;
   2599         const float *frameIn = framesIn;
   2600 
   2601         for (ma_uint32 frame = 0; frame < frameCount; frame++)
   2602         {
   2603             frameOut[0] += (frameIn[0]*levels[0]);
   2604             frameOut[1] += (frameIn[1]*levels[1]);
   2605 
   2606             frameOut += 2;
   2607             frameIn += 2;
   2608         }
   2609     }
   2610     else  // We do not consider panning
   2611     {
   2612         for (ma_uint32 frame = 0; frame < frameCount; frame++)
   2613         {
   2614             for (ma_uint32 c = 0; c < channels; c++)
   2615             {
   2616                 float *frameOut = framesOut + (frame*channels);
   2617                 const float *frameIn = framesIn + (frame*channels);
   2618 
   2619                 // Output accumulates input multiplied by volume to provided output (usually 0)
   2620                 frameOut[c] += (frameIn[c]*localVolume);
   2621             }
   2622         }
   2623     }
   2624 }
   2625 
   2626 // Check if an audio buffer is playing, assuming the audio system mutex has been locked
   2627 static bool IsAudioBufferPlayingInLockedState(AudioBuffer *buffer)
   2628 {
   2629     bool result = false;
   2630 
   2631     if (buffer != NULL) result = (buffer->playing && !buffer->paused);
   2632 
   2633     return result;
   2634 }
   2635 
   2636 // Stop an audio buffer, assuming the audio system mutex has been locked
   2637 static void StopAudioBufferInLockedState(AudioBuffer *buffer)
   2638 {
   2639     if (buffer != NULL)
   2640     {
   2641         if (IsAudioBufferPlayingInLockedState(buffer))
   2642         {
   2643             buffer->playing = false;
   2644             buffer->paused = false;
   2645             buffer->frameCursorPos = 0;
   2646             buffer->framesProcessed = 0;
   2647             buffer->isSubBufferProcessed[0] = true;
   2648             buffer->isSubBufferProcessed[1] = true;
   2649         }
   2650     }
   2651 }
   2652 
   2653 // Update audio stream, assuming the audio system mutex has been locked
   2654 static void UpdateAudioStreamInLockedState(AudioStream stream, const void *data, int frameCount)
   2655 {
   2656     if (stream.buffer != NULL)
   2657     {
   2658         if (stream.buffer->isSubBufferProcessed[0] || stream.buffer->isSubBufferProcessed[1])
   2659         {
   2660             ma_uint32 subBufferToUpdate = 0;
   2661 
   2662             if (stream.buffer->isSubBufferProcessed[0] && stream.buffer->isSubBufferProcessed[1])
   2663             {
   2664                 // Both buffers are available for updating
   2665                 // Update the first one and make sure the cursor is moved back to the front
   2666                 subBufferToUpdate = 0;
   2667                 stream.buffer->frameCursorPos = 0;
   2668             }
   2669             else
   2670             {
   2671                 // Just update whichever sub-buffer is processed
   2672                 subBufferToUpdate = (stream.buffer->isSubBufferProcessed[0])? 0 : 1;
   2673             }
   2674 
   2675             ma_uint32 subBufferSizeInFrames = stream.buffer->sizeInFrames/2;
   2676             unsigned char *subBuffer = stream.buffer->data + ((subBufferSizeInFrames*stream.channels*(stream.sampleSize/8))*subBufferToUpdate);
   2677 
   2678             // Total frames processed in buffer is always the complete size, filled with 0 if required
   2679             stream.buffer->framesProcessed += subBufferSizeInFrames;
   2680 
   2681             // Does this API expect a whole buffer to be updated in one go?
   2682             // Assuming so, but if not will need to change this logic
   2683             if (subBufferSizeInFrames >= (ma_uint32)frameCount)
   2684             {
   2685                 ma_uint32 framesToWrite = (ma_uint32)frameCount;
   2686 
   2687                 ma_uint32 bytesToWrite = framesToWrite*stream.channels*(stream.sampleSize/8);
   2688                 memcpy(subBuffer, data, bytesToWrite);
   2689 
   2690                 // Any leftover frames should be filled with zeros
   2691                 ma_uint32 leftoverFrameCount = subBufferSizeInFrames - framesToWrite;
   2692 
   2693                 if (leftoverFrameCount > 0) memset(subBuffer + bytesToWrite, 0, leftoverFrameCount*stream.channels*(stream.sampleSize/8));
   2694 
   2695                 stream.buffer->isSubBufferProcessed[subBufferToUpdate] = false;
   2696             }
   2697             else TRACELOG(LOG_WARNING, "STREAM: Attempting to write too many frames to buffer");
   2698         }
   2699         else TRACELOG(LOG_WARNING, "STREAM: Buffer not available for updating");
   2700     }
   2701 }
   2702 
   2703 // Some required functions for audio standalone module version
   2704 #if defined(RAUDIO_STANDALONE)
   2705 // Check file extension
   2706 static bool IsFileExtension(const char *fileName, const char *ext)
   2707 {
   2708     bool result = false;
   2709     const char *fileExt;
   2710 
   2711     if ((fileExt = strrchr(fileName, '.')) != NULL)
   2712     {
   2713         if (strcmp(fileExt, ext) == 0) result = true;
   2714     }
   2715 
   2716     return result;
   2717 }
   2718 
   2719 // Get pointer to extension for a filename string (includes the dot: .png)
   2720 static const char *GetFileExtension(const char *fileName)
   2721 {
   2722     const char *dot = strrchr(fileName, '.');
   2723 
   2724     if (!dot || dot == fileName) return NULL;
   2725 
   2726     return dot;
   2727 }
   2728 
   2729 // String pointer reverse break: returns right-most occurrence of charset in s
   2730 static const char *strprbrk(const char *s, const char *charset)
   2731 {
   2732     const char *latestMatch = NULL;
   2733     for (; s = strpbrk(s, charset), s != NULL; latestMatch = s++) { }
   2734     return latestMatch;
   2735 }
   2736 
   2737 // Get pointer to filename for a path string
   2738 static const char *GetFileName(const char *filePath)
   2739 {
   2740     const char *fileName = NULL;
   2741     if (filePath != NULL) fileName = strprbrk(filePath, "\\/");
   2742 
   2743     if (!fileName) return filePath;
   2744 
   2745     return fileName + 1;
   2746 }
   2747 
   2748 // Get filename string without extension (uses static string)
   2749 static const char *GetFileNameWithoutExt(const char *filePath)
   2750 {
   2751     #define MAX_FILENAMEWITHOUTEXT_LENGTH   256
   2752 
   2753     static char fileName[MAX_FILENAMEWITHOUTEXT_LENGTH] = { 0 };
   2754     memset(fileName, 0, MAX_FILENAMEWITHOUTEXT_LENGTH);
   2755 
   2756     if (filePath != NULL) strcpy(fileName, GetFileName(filePath));   // Get filename with extension
   2757 
   2758     int size = (int)strlen(fileName);   // Get size in bytes
   2759 
   2760     for (int i = 0; (i < size) && (i < MAX_FILENAMEWITHOUTEXT_LENGTH); i++)
   2761     {
   2762         if (fileName[i] == '.')
   2763         {
   2764             // NOTE: We break on first '.' found
   2765             fileName[i] = '\0';
   2766             break;
   2767         }
   2768     }
   2769 
   2770     return fileName;
   2771 }
   2772 
   2773 // Load data from file into a buffer
   2774 static unsigned char *LoadFileData(const char *fileName, int *dataSize)
   2775 {
   2776     unsigned char *data = NULL;
   2777     *dataSize = 0;
   2778 
   2779     if (fileName != NULL)
   2780     {
   2781         FILE *file = fopen(fileName, "rb");
   2782 
   2783         if (file != NULL)
   2784         {
   2785             // WARNING: On binary streams SEEK_END could not be found,
   2786             // using fseek() and ftell() could not work in some (rare) cases
   2787             fseek(file, 0, SEEK_END);
   2788             int size = ftell(file);
   2789             fseek(file, 0, SEEK_SET);
   2790 
   2791             if (size > 0)
   2792             {
   2793                 data = (unsigned char *)RL_MALLOC(size*sizeof(unsigned char));
   2794 
   2795                 // NOTE: fread() returns number of read elements instead of bytes, so we read [1 byte, size elements]
   2796                 unsigned int count = (unsigned int)fread(data, sizeof(unsigned char), size, file);
   2797                 *dataSize = count;
   2798 
   2799                 if (count != size) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially loaded", fileName);
   2800                 else TRACELOG(LOG_INFO, "FILEIO: [%s] File loaded successfully", fileName);
   2801             }
   2802             else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to read file", fileName);
   2803 
   2804             fclose(file);
   2805         }
   2806         else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", fileName);
   2807     }
   2808     else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
   2809 
   2810     return data;
   2811 }
   2812 
   2813 // Save data to file from buffer
   2814 static bool SaveFileData(const char *fileName, void *data, int dataSize)
   2815 {
   2816     if (fileName != NULL)
   2817     {
   2818         FILE *file = fopen(fileName, "wb");
   2819 
   2820         if (file != NULL)
   2821         {
   2822             unsigned int count = (unsigned int)fwrite(data, sizeof(unsigned char), dataSize, file);
   2823 
   2824             if (count == 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write file", fileName);
   2825             else if (count != dataSize) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially written", fileName);
   2826             else TRACELOG(LOG_INFO, "FILEIO: [%s] File saved successfully", fileName);
   2827 
   2828             fclose(file);
   2829         }
   2830         else
   2831         {
   2832             TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", fileName);
   2833             return false;
   2834         }
   2835     }
   2836     else
   2837     {
   2838         TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
   2839         return false;
   2840     }
   2841 
   2842     return true;
   2843 }
   2844 
   2845 // Save text data to file (write), string must be '\0' terminated
   2846 static bool SaveFileText(const char *fileName, char *text)
   2847 {
   2848     if (fileName != NULL)
   2849     {
   2850         FILE *file = fopen(fileName, "wt");
   2851 
   2852         if (file != NULL)
   2853         {
   2854             int count = fprintf(file, "%s", text);
   2855 
   2856             if (count == 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write text file", fileName);
   2857             else TRACELOG(LOG_INFO, "FILEIO: [%s] Text file saved successfully", fileName);
   2858 
   2859             fclose(file);
   2860         }
   2861         else
   2862         {
   2863             TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open text file", fileName);
   2864             return false;
   2865         }
   2866     }
   2867     else
   2868     {
   2869         TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
   2870         return false;
   2871     }
   2872 
   2873     return true;
   2874 }
   2875 #endif
   2876 
   2877 #undef AudioBuffer
   2878 
   2879 #endif      // SUPPORT_MODULE_RAUDIO