App-MHFS

 view release on metacpan or  search on metacpan

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN

    #endif

    /* If at this point we still haven't determined compiler support for the intrinsics just fall back to __has_include. */
    #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include)
        #if !defined(MA_SUPPORT_SSE2)   && !defined(MA_NO_SSE2)   && __has_include(<emmintrin.h>)
            #define MA_SUPPORT_SSE2
        #endif
        /*#if !defined(MA_SUPPORT_AVX)    && !defined(MA_NO_AVX)    && __has_include(<immintrin.h>)*/
        /*    #define MA_SUPPORT_AVX*/
        /*#endif*/
        #if !defined(MA_SUPPORT_AVX2)   && !defined(MA_NO_AVX2)   && __has_include(<immintrin.h>)
            #define MA_SUPPORT_AVX2
        #endif
    #endif

    #if defined(MA_SUPPORT_AVX2) || defined(MA_SUPPORT_AVX)
        #include <immintrin.h>
    #elif defined(MA_SUPPORT_SSE2)
        #include <emmintrin.h>
    #endif
#endif

#if defined(MA_ARM)
    #if !defined(MA_NO_NEON) && (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64))
        #define MA_SUPPORT_NEON
        #include <arm_neon.h>
    #endif
#endif

/* Begin globally disabled warnings. */
#if defined(_MSC_VER)
    #pragma warning(push)
    #pragma warning(disable:4752)   /* found Intel(R) Advanced Vector Extensions; consider using /arch:AVX */
    #pragma warning(disable:4049)   /* compiler limit : terminating line number emission */
#endif

#if defined(MA_X64) || defined(MA_X86)
    #if defined(_MSC_VER) && !defined(__clang__)
        #if _MSC_VER >= 1400
            #include <intrin.h>
            static MA_INLINE void ma_cpuid(int info[4], int fid)
            {
                __cpuid(info, fid);
            }
        #else
            #define MA_NO_CPUID
        #endif

        #if _MSC_VER >= 1600 && (defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 160040219)
            static MA_INLINE unsigned __int64 ma_xgetbv(int reg)
            {
                return _xgetbv(reg);
            }
        #else
            #define MA_NO_XGETBV
        #endif
    #elif (defined(__GNUC__) || defined(__clang__)) && !defined(MA_ANDROID)
        static MA_INLINE void ma_cpuid(int info[4], int fid)
        {
            /*
            It looks like the -fPIC option uses the ebx register which GCC complains about. We can work around this by just using a different register, the
            specific register of which I'm letting the compiler decide on. The "k" prefix is used to specify a 32-bit register. The {...} syntax is for
            supporting different assembly dialects.

            What's basically happening is that we're saving and restoring the ebx register manually.
            */
            #if defined(DRFLAC_X86) && defined(__PIC__)
                __asm__ __volatile__ (
                    "xchg{l} {%%}ebx, %k1;"
                    "cpuid;"
                    "xchg{l} {%%}ebx, %k1;"
                    : "=a"(info[0]), "=&r"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0)
                );
            #else
                __asm__ __volatile__ (
                    "cpuid" : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0)
                );
            #endif
        }

        static MA_INLINE ma_uint64 ma_xgetbv(int reg)
        {
            unsigned int hi;
            unsigned int lo;

            __asm__ __volatile__ (
                "xgetbv" : "=a"(lo), "=d"(hi) : "c"(reg)
            );

            return ((ma_uint64)hi << 32) | (ma_uint64)lo;
        }
    #else
        #define MA_NO_CPUID
        #define MA_NO_XGETBV
    #endif
#else
    #define MA_NO_CPUID
    #define MA_NO_XGETBV
#endif

static MA_INLINE ma_bool32 ma_has_sse2(void)
{
#if defined(MA_SUPPORT_SSE2)
    #if (defined(MA_X64) || defined(MA_X86)) && !defined(MA_NO_SSE2)
        #if defined(MA_X64)
            return MA_TRUE;    /* 64-bit targets always support SSE2. */
        #elif (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__)
            return MA_TRUE;    /* If the compiler is allowed to freely generate SSE2 code we can assume support. */
        #else
            #if defined(MA_NO_CPUID)
                return MA_FALSE;
            #else
                int info[4];
                ma_cpuid(info, 1);
                return (info[3] & (1 << 26)) != 0;
            #endif
        #endif
    #else
        return MA_FALSE;       /* SSE2 is only supported on x86 and x64 architectures. */
    #endif
#else

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN


/*
Unfortunately using runtime linking for pthreads causes problems. This has occurred for me when testing on FreeBSD. When
using runtime linking, deadlocks can occur (for me it happens when loading data from fread()). It turns out that doing
compile-time linking fixes this. I'm not sure why this happens, but the safest way I can think of to fix this is to simply
disable runtime linking by default. To enable runtime linking, #define this before the implementation of this file. I am
not officially supporting this, but I'm leaving it here in case it's useful for somebody, somewhere.
*/
/*#define MA_USE_RUNTIME_LINKING_FOR_PTHREAD*/

/* Disable run-time linking on certain backends. */
#ifndef MA_NO_RUNTIME_LINKING
    #if defined(MA_EMSCRIPTEN)
        #define MA_NO_RUNTIME_LINKING
    #endif
#endif


MA_API void ma_device_info_add_native_data_format(ma_device_info* pDeviceInfo, ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 flags)
{
    if (pDeviceInfo == NULL) {
        return;
    }

    if (pDeviceInfo->nativeDataFormatCount < ma_countof(pDeviceInfo->nativeDataFormats)) {
        pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].format     = format;
        pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].channels   = channels;
        pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].sampleRate = sampleRate;
        pDeviceInfo->nativeDataFormats[pDeviceInfo->nativeDataFormatCount].flags      = flags;
        pDeviceInfo->nativeDataFormatCount += 1;
    }
}


MA_API const char* ma_get_backend_name(ma_backend backend)
{
    switch (backend)
    {
        case ma_backend_wasapi:     return "WASAPI";
        case ma_backend_dsound:     return "DirectSound";
        case ma_backend_winmm:      return "WinMM";
        case ma_backend_coreaudio:  return "Core Audio";
        case ma_backend_sndio:      return "sndio";
        case ma_backend_audio4:     return "audio(4)";
        case ma_backend_oss:        return "OSS";
        case ma_backend_pulseaudio: return "PulseAudio";
        case ma_backend_alsa:       return "ALSA";
        case ma_backend_jack:       return "JACK";
        case ma_backend_aaudio:     return "AAudio";
        case ma_backend_opensl:     return "OpenSL|ES";
        case ma_backend_webaudio:   return "Web Audio";
        case ma_backend_custom:     return "Custom";
        case ma_backend_null:       return "Null";
        default:                    return "Unknown";
    }
}

MA_API ma_bool32 ma_is_backend_enabled(ma_backend backend)
{
    /*
    This looks a little bit gross, but we want all backends to be included in the switch to avoid warnings on some compilers
    about some enums not being handled by the switch statement.
    */
    switch (backend)
    {
        case ma_backend_wasapi:
        #if defined(MA_HAS_WASAPI)
            return MA_TRUE;
        #else
            return MA_FALSE;
        #endif
        case ma_backend_dsound:
        #if defined(MA_HAS_DSOUND)
            return MA_TRUE;
        #else
            return MA_FALSE;
        #endif
        case ma_backend_winmm:
        #if defined(MA_HAS_WINMM)
            return MA_TRUE;
        #else
            return MA_FALSE;
        #endif
        case ma_backend_coreaudio:
        #if defined(MA_HAS_COREAUDIO)
            return MA_TRUE;
        #else
            return MA_FALSE;
        #endif
        case ma_backend_sndio:
        #if defined(MA_HAS_SNDIO)
            return MA_TRUE;
        #else
            return MA_FALSE;
        #endif
        case ma_backend_audio4:
        #if defined(MA_HAS_AUDIO4)
            return MA_TRUE;
        #else
            return MA_FALSE;
        #endif
        case ma_backend_oss:
        #if defined(MA_HAS_OSS)
            return MA_TRUE;
        #else
            return MA_FALSE;
        #endif
        case ma_backend_pulseaudio:
        #if defined(MA_HAS_PULSEAUDIO)
            return MA_TRUE;
        #else
            return MA_FALSE;
        #endif
        case ma_backend_alsa:
        #if defined(MA_HAS_ALSA)
            return MA_TRUE;
        #else
            return MA_FALSE;
        #endif
        case ma_backend_jack:
        #if defined(MA_HAS_JACK)

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN


    /*
    We need to register a notification client to detect when the device has been disabled, unplugged or re-routed (when the default device changes). When
    we are connecting to the default device we want to do automatic stream routing when the device is disabled or unplugged. Otherwise we want to just
    stop the device outright and let the application handle it.
    */
#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK)
    if (pConfig->wasapi.noAutoStreamRouting == MA_FALSE) {
        if ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pConfig->capture.pDeviceID == NULL) {
            pDevice->wasapi.allowCaptureAutoStreamRouting = MA_TRUE;
        }
        if ((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pConfig->playback.pDeviceID == NULL) {
            pDevice->wasapi.allowPlaybackAutoStreamRouting = MA_TRUE;
        }
    }

    hr = ma_CoCreateInstance(pDevice->pContext, MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator);
    if (FAILED(hr)) {
        ma_device_uninit__wasapi(pDevice);
        ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create device enumerator.");
        return ma_result_from_HRESULT(hr);
    }

    pDevice->wasapi.notificationClient.lpVtbl  = (void*)&g_maNotificationCientVtbl;
    pDevice->wasapi.notificationClient.counter = 1;
    pDevice->wasapi.notificationClient.pDevice = pDevice;

    hr = pDeviceEnumerator->lpVtbl->RegisterEndpointNotificationCallback(pDeviceEnumerator, &pDevice->wasapi.notificationClient);
    if (SUCCEEDED(hr)) {
        pDevice->wasapi.pDeviceEnumerator = (ma_ptr)pDeviceEnumerator;
    } else {
        /* Not the end of the world if we fail to register the notification callback. We just won't support automatic stream routing. */
        ma_IMMDeviceEnumerator_Release(pDeviceEnumerator);
    }
#endif

    c89atomic_exchange_32(&pDevice->wasapi.isStartedCapture,  MA_FALSE);
    c89atomic_exchange_32(&pDevice->wasapi.isStartedPlayback, MA_FALSE);

    return MA_SUCCESS;
}

static ma_result ma_device__get_available_frames__wasapi(ma_device* pDevice, ma_IAudioClient* pAudioClient, ma_uint32* pFrameCount)
{
    ma_uint32 paddingFramesCount;
    HRESULT hr;
    ma_share_mode shareMode;

    MA_ASSERT(pDevice != NULL);
    MA_ASSERT(pFrameCount != NULL);

    *pFrameCount = 0;

    if ((ma_ptr)pAudioClient != pDevice->wasapi.pAudioClientPlayback && (ma_ptr)pAudioClient != pDevice->wasapi.pAudioClientCapture) {
        return MA_INVALID_OPERATION;
    }

    /*
    I've had a report that GetCurrentPadding() is returning a frame count of 0 which is preventing
    higher level function calls from doing anything because it thinks nothing is available. I have
    taken a look at the documentation and it looks like this is unnecessary in exclusive mode.

    From Microsoft's documentation:

        For an exclusive-mode rendering or capture stream that was initialized with the
        AUDCLNT_STREAMFLAGS_EVENTCALLBACK flag, the client typically has no use for the padding
        value reported by GetCurrentPadding. Instead, the client accesses an entire buffer during
        each processing pass.

    Considering this, I'm going to skip GetCurrentPadding() for exclusive mode and just report the
    entire buffer. This depends on the caller making sure they wait on the event handler.
    */
    shareMode = ((ma_ptr)pAudioClient == pDevice->wasapi.pAudioClientPlayback) ? pDevice->playback.shareMode : pDevice->capture.shareMode;
    if (shareMode == ma_share_mode_shared) {
        /* Shared mode. */
        hr = ma_IAudioClient_GetCurrentPadding(pAudioClient, &paddingFramesCount);
        if (FAILED(hr)) {
            return ma_result_from_HRESULT(hr);
        }

        if ((ma_ptr)pAudioClient == pDevice->wasapi.pAudioClientPlayback) {
            *pFrameCount = pDevice->wasapi.actualBufferSizeInFramesPlayback - paddingFramesCount;
        } else {
            *pFrameCount = paddingFramesCount;
        }
    } else {
        /* Exclusive mode. */
        if ((ma_ptr)pAudioClient == pDevice->wasapi.pAudioClientPlayback) {
            *pFrameCount = pDevice->wasapi.actualBufferSizeInFramesPlayback;
        } else {
            *pFrameCount = pDevice->wasapi.actualBufferSizeInFramesCapture;
        }
    }

    return MA_SUCCESS;
}


static ma_result ma_device_reroute__wasapi(ma_device* pDevice, ma_device_type deviceType)
{
    ma_result result;

    if (deviceType == ma_device_type_duplex) {
        return MA_INVALID_ARGS;
    }

    ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "=== CHANGING DEVICE ===\n");

    result = ma_device_reinit__wasapi(pDevice, deviceType);
    if (result != MA_SUCCESS) {
        ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[WASAPI] Reinitializing device after route change failed.\n");
        return result;
    }

    ma_device__post_init_setup(pDevice, deviceType);

    ma_device__on_notification_rerouted(pDevice);

    return MA_SUCCESS;
}

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN

    *ppPCM = NULL;
    pPCM = NULL;

    stream = (deviceType == ma_device_type_playback) ? MA_SND_PCM_STREAM_PLAYBACK : MA_SND_PCM_STREAM_CAPTURE;

    if (pDeviceID == NULL) {
        ma_bool32 isDeviceOpen;
        size_t i;

        /*
        We're opening the default device. I don't know if trying anything other than "default" is necessary, but it makes
        me feel better to try as hard as we can get to get _something_ working.
        */
        const char* defaultDeviceNames[] = {
            "default",
            NULL,
            NULL,
            NULL,
            NULL,
            NULL,
            NULL
        };

        if (shareMode == ma_share_mode_exclusive) {
            defaultDeviceNames[1] = "hw";
            defaultDeviceNames[2] = "hw:0";
            defaultDeviceNames[3] = "hw:0,0";
        } else {
            if (deviceType == ma_device_type_playback) {
                defaultDeviceNames[1] = "dmix";
                defaultDeviceNames[2] = "dmix:0";
                defaultDeviceNames[3] = "dmix:0,0";
            } else {
                defaultDeviceNames[1] = "dsnoop";
                defaultDeviceNames[2] = "dsnoop:0";
                defaultDeviceNames[3] = "dsnoop:0,0";
            }
            defaultDeviceNames[4] = "hw";
            defaultDeviceNames[5] = "hw:0";
            defaultDeviceNames[6] = "hw:0,0";
        }

        isDeviceOpen = MA_FALSE;
        for (i = 0; i < ma_countof(defaultDeviceNames); ++i) {
            if (defaultDeviceNames[i] != NULL && defaultDeviceNames[i][0] != '\0') {
                if (((ma_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)(&pPCM, defaultDeviceNames[i], stream, openMode) == 0) {
                    isDeviceOpen = MA_TRUE;
                    break;
                }
            }
        }

        if (!isDeviceOpen) {
            ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_open() failed when trying to open an appropriate default device.");
            return MA_FAILED_TO_OPEN_BACKEND_DEVICE;
        }
    } else {
        /*
        We're trying to open a specific device. There's a few things to consider here:

        miniaudio recongnizes a special format of device id that excludes the "hw", "dmix", etc. prefix. It looks like this: ":0,0", ":0,1", etc. When
        an ID of this format is specified, it indicates to miniaudio that it can try different combinations of plugins ("hw", "dmix", etc.) until it
        finds an appropriate one that works. This comes in very handy when trying to open a device in shared mode ("dmix"), vs exclusive mode ("hw").
        */

        /* May end up needing to make small adjustments to the ID, so make a copy. */
        ma_device_id deviceID = *pDeviceID;
        int resultALSA = -ENODEV;

        if (deviceID.alsa[0] != ':') {
            /* The ID is not in ":0,0" format. Use the ID exactly as-is. */
            resultALSA = ((ma_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)(&pPCM, deviceID.alsa, stream, openMode);
        } else {
            char hwid[256];

            /* The ID is in ":0,0" format. Try different plugins depending on the shared mode. */
            if (deviceID.alsa[1] == '\0') {
                deviceID.alsa[0] = '\0';  /* An ID of ":" should be converted to "". */
            }

            if (shareMode == ma_share_mode_shared) {
                if (deviceType == ma_device_type_playback) {
                    ma_strcpy_s(hwid, sizeof(hwid), "dmix");
                } else {
                    ma_strcpy_s(hwid, sizeof(hwid), "dsnoop");
                }

                if (ma_strcat_s(hwid, sizeof(hwid), deviceID.alsa) == 0) {
                    resultALSA = ((ma_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)(&pPCM, hwid, stream, openMode);
                }
            }

            /* If at this point we still don't have an open device it means we're either preferencing exclusive mode or opening with "dmix"/"dsnoop" failed. */
            if (resultALSA != 0) {
                ma_strcpy_s(hwid, sizeof(hwid), "hw");
                if (ma_strcat_s(hwid, sizeof(hwid), deviceID.alsa) == 0) {
                    resultALSA = ((ma_snd_pcm_open_proc)pContext->alsa.snd_pcm_open)(&pPCM, hwid, stream, openMode);
                }
            }
        }

        if (resultALSA < 0) {
            ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[ALSA] snd_pcm_open() failed.");
            return ma_result_from_errno(-resultALSA);
        }
    }

    *ppPCM = pPCM;
    return MA_SUCCESS;
}


static ma_result ma_context_enumerate_devices__alsa(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData)
{
    int resultALSA;
    ma_bool32 cbResult = MA_TRUE;
    char** ppDeviceHints;
    ma_device_id* pUniqueIDs = NULL;
    ma_uint32 uniqueIDCount = 0;
    char** ppNextDeviceHint;

    MA_ASSERT(pContext != NULL);
    MA_ASSERT(callback != NULL);

    ma_mutex_lock(&pContext->alsa.internalDeviceEnumLock);

    resultALSA = ((ma_snd_device_name_hint_proc)pContext->alsa.snd_device_name_hint)(-1, "pcm", (void***)&ppDeviceHints);
    if (resultALSA < 0) {
        ma_mutex_unlock(&pContext->alsa.internalDeviceEnumLock);
        return ma_result_from_errno(-resultALSA);
    }

    ppNextDeviceHint = ppDeviceHints;
    while (*ppNextDeviceHint != NULL) {
        char* NAME = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "NAME");
        char* DESC = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "DESC");
        char* IOID = ((ma_snd_device_name_get_hint_proc)pContext->alsa.snd_device_name_get_hint)(*ppNextDeviceHint, "IOID");
        ma_device_type deviceType = ma_device_type_playback;
        ma_bool32 stopEnumeration = MA_FALSE;
        char hwid[sizeof(pUniqueIDs->alsa)];
        ma_device_info deviceInfo;

        if ((IOID == NULL || ma_strcmp(IOID, "Output") == 0)) {
            deviceType = ma_device_type_playback;
        }
        if ((IOID != NULL && ma_strcmp(IOID, "Input" ) == 0)) {
            deviceType = ma_device_type_capture;
        }

        if (NAME != NULL) {
            if (pContext->alsa.useVerboseDeviceEnumeration) {
                /* Verbose mode. Use the name exactly as-is. */
                ma_strncpy_s(hwid, sizeof(hwid), NAME, (size_t)-1);
            } else {
                /* Simplified mode. Use ":%d,%d" format. */
                if (ma_convert_device_name_to_hw_format__alsa(pContext, hwid, sizeof(hwid), NAME) == 0) {
                    /*
                    At this point, hwid looks like "hw:0,0". In simplified enumeration mode, we actually want to strip off the
                    plugin name so it looks like ":0,0". The reason for this is that this special format is detected at device
                    initialization time and is used as an indicator to try and use the most appropriate plugin depending on the
                    device type and sharing mode.
                    */
                    char* dst = hwid;
                    char* src = hwid+2;
                    while ((*dst++ = *src++));
                } else {
                    /* Conversion to "hw:%d,%d" failed. Just use the name as-is. */
                    ma_strncpy_s(hwid, sizeof(hwid), NAME, (size_t)-1);
                }

                if (ma_does_id_exist_in_list__alsa(pUniqueIDs, uniqueIDCount, hwid)) {
                    goto next_device;   /* The device has already been enumerated. Move on to the next one. */
                } else {
                    /* The device has not yet been enumerated. Make sure it's added to our list so that it's not enumerated again. */
                    size_t newCapacity = sizeof(*pUniqueIDs) * (uniqueIDCount + 1);
                    ma_device_id* pNewUniqueIDs = (ma_device_id*)ma_realloc(pUniqueIDs, newCapacity, &pContext->allocationCallbacks);
                    if (pNewUniqueIDs == NULL) {
                        goto next_device;   /* Failed to allocate memory. */
                    }

                    pUniqueIDs = pNewUniqueIDs;
                    MA_COPY_MEMORY(pUniqueIDs[uniqueIDCount].alsa, hwid, sizeof(hwid));
                    uniqueIDCount += 1;
                }
            }
        } else {
            MA_ZERO_MEMORY(hwid, sizeof(hwid));
        }

        MA_ZERO_OBJECT(&deviceInfo);
        ma_strncpy_s(deviceInfo.id.alsa, sizeof(deviceInfo.id.alsa), hwid, (size_t)-1);

        /*
        There's no good way to determine whether or not a device is the default on Linux. We're just going to do something simple and
        just use the name of "default" as the indicator.
        */
        if (ma_strcmp(deviceInfo.id.alsa, "default") == 0) {
            deviceInfo.isDefault = MA_TRUE;
        }


        /*
        DESC is the friendly name. We treat this slightly differently depending on whether or not we are using verbose
        device enumeration. In verbose mode we want to take the entire description so that the end-user can distinguish
        between the subdevices of each card/dev pair. In simplified mode, however, we only want the first part of the
        description.

        The value in DESC seems to be split into two lines, with the first line being the name of the device and the
        second line being a description of the device. I don't like having the description be across two lines because
        it makes formatting ugly and annoying. I'm therefore deciding to put it all on a single line with the second line
        being put into parentheses. In simplified mode I'm just stripping the second line entirely.
        */
        if (DESC != NULL) {
            int lfPos;
            const char* line2 = ma_find_char(DESC, '\n', &lfPos);
            if (line2 != NULL) {
                line2 += 1; /* Skip past the new-line character. */

                if (pContext->alsa.useVerboseDeviceEnumeration) {

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN

            formatALSA = MA_SND_PCM_FORMAT_UNKNOWN;
            for (iFormat = 0; iFormat < ma_countof(g_maFormatPriorities); ++iFormat) {
                if (((ma_snd_pcm_hw_params_test_format_proc)pDevice->pContext->alsa.snd_pcm_hw_params_test_format)(pPCM, pHWParams, ma_convert_ma_format_to_alsa_format(g_maFormatPriorities[iFormat])) == 0) {
                    formatALSA = ma_convert_ma_format_to_alsa_format(g_maFormatPriorities[iFormat]);
                    break;
                }
            }

            if (formatALSA == MA_SND_PCM_FORMAT_UNKNOWN) {
                ma_free(pHWParams, &pDevice->pContext->allocationCallbacks);
                ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
                ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Format not supported. The device does not support any miniaudio formats.");
                return MA_FORMAT_NOT_SUPPORTED;
            }
        }

        resultALSA = ((ma_snd_pcm_hw_params_set_format_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_format)(pPCM, pHWParams, formatALSA);
        if (resultALSA < 0) {
            ma_free(pHWParams, &pDevice->pContext->allocationCallbacks);
            ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
            ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Format not supported. snd_pcm_hw_params_set_format() failed.");
            return ma_result_from_errno(-resultALSA);
        }

        internalFormat = ma_format_from_alsa(formatALSA);
        if (internalFormat == ma_format_unknown) {
            ma_free(pHWParams, &pDevice->pContext->allocationCallbacks);
            ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
            ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] The chosen format is not supported by miniaudio.");
            return MA_FORMAT_NOT_SUPPORTED;
        }
    }

    /* Channels. */
    {
        unsigned int channels = pDescriptor->channels;
        if (channels == 0) {
            channels = MA_DEFAULT_CHANNELS;
        }

        resultALSA = ((ma_snd_pcm_hw_params_set_channels_near_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_channels_near)(pPCM, pHWParams, &channels);
        if (resultALSA < 0) {
            ma_free(pHWParams, &pDevice->pContext->allocationCallbacks);
            ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
            ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set channel count. snd_pcm_hw_params_set_channels_near() failed.");
            return ma_result_from_errno(-resultALSA);
        }

        internalChannels = (ma_uint32)channels;
    }

    /* Sample Rate */
    {
        unsigned int sampleRate;

        /*
        It appears there's either a bug in ALSA, a bug in some drivers, or I'm doing something silly; but having resampling enabled causes
        problems with some device configurations when used in conjunction with MMAP access mode. To fix this problem we need to disable
        resampling.

        To reproduce this problem, open the "plug:dmix" device, and set the sample rate to 44100. Internally, it looks like dmix uses a
        sample rate of 48000. The hardware parameters will get set correctly with no errors, but it looks like the 44100 -> 48000 resampling
        doesn't work properly - but only with MMAP access mode. You will notice skipping/crackling in the audio, and it'll run at a slightly
        faster rate.

        miniaudio has built-in support for sample rate conversion (albeit low quality at the moment), so disabling resampling should be fine
        for us. The only problem is that it won't be taking advantage of any kind of hardware-accelerated resampling and it won't be very
        good quality until I get a chance to improve the quality of miniaudio's software sample rate conversion.

        I don't currently know if the dmix plugin is the only one with this error. Indeed, this is the only one I've been able to reproduce
        this error with. In the future, we may want to restrict the disabling of resampling to only known bad plugins.
        */
        ((ma_snd_pcm_hw_params_set_rate_resample_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_rate_resample)(pPCM, pHWParams, 0);

        sampleRate = pDescriptor->sampleRate;
        if (sampleRate == 0) {
            sampleRate = MA_DEFAULT_SAMPLE_RATE;
        }

        resultALSA = ((ma_snd_pcm_hw_params_set_rate_near_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_rate_near)(pPCM, pHWParams, &sampleRate, 0);
        if (resultALSA < 0) {
            ma_free(pHWParams, &pDevice->pContext->allocationCallbacks);
            ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
            ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Sample rate not supported. snd_pcm_hw_params_set_rate_near() failed.");
            return ma_result_from_errno(-resultALSA);
        }

        internalSampleRate = (ma_uint32)sampleRate;
    }

    /* Periods. */
    {
        ma_uint32 periods = pDescriptor->periodCount;

        resultALSA = ((ma_snd_pcm_hw_params_set_periods_near_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_periods_near)(pPCM, pHWParams, &periods, NULL);
        if (resultALSA < 0) {
            ma_free(pHWParams, &pDevice->pContext->allocationCallbacks);
            ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
            ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set period count. snd_pcm_hw_params_set_periods_near() failed.");
            return ma_result_from_errno(-resultALSA);
        }

        internalPeriods = periods;
    }

    /* Buffer Size */
    {
        ma_snd_pcm_uframes_t actualBufferSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptor, internalSampleRate, pConfig->performanceProfile) * internalPeriods;

        resultALSA = ((ma_snd_pcm_hw_params_set_buffer_size_near_proc)pDevice->pContext->alsa.snd_pcm_hw_params_set_buffer_size_near)(pPCM, pHWParams, &actualBufferSizeInFrames);
        if (resultALSA < 0) {
            ma_free(pHWParams, &pDevice->pContext->allocationCallbacks);
            ((ma_snd_pcm_close_proc)pDevice->pContext->alsa.snd_pcm_close)(pPCM);
            ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to set buffer size for device. snd_pcm_hw_params_set_buffer_size() failed.");
            return ma_result_from_errno(-resultALSA);
        }

        internalPeriodSizeInFrames = actualBufferSizeInFrames / internalPeriods;
    }

    /* Apply hardware parameters. */
    resultALSA = ((ma_snd_pcm_hw_params_proc)pDevice->pContext->alsa.snd_pcm_hw_params)(pPCM, pHWParams);

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN

                }
            }

            if (!found) {
                return MA_DOES_NOT_EXIST;
            }
        } else {
            if (deviceType == ma_device_type_playback) {
                ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
            } else {
                ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
            }
        }


        /*
        Retrieving device information is more annoying on mobile than desktop. For simplicity I'm locking this down to whatever format is
        reported on a temporary I/O unit. The problem, however, is that this doesn't return a value for the sample rate which we need to
        retrieve from the AVAudioSession shared instance.
        */
        desc.componentType = kAudioUnitType_Output;
        desc.componentSubType = kAudioUnitSubType_RemoteIO;
        desc.componentManufacturer = kAudioUnitManufacturer_Apple;
        desc.componentFlags = 0;
        desc.componentFlagsMask = 0;

        component = ((ma_AudioComponentFindNext_proc)pContext->coreaudio.AudioComponentFindNext)(NULL, &desc);
        if (component == NULL) {
            return MA_FAILED_TO_INIT_BACKEND;
        }

        status = ((ma_AudioComponentInstanceNew_proc)pContext->coreaudio.AudioComponentInstanceNew)(component, &audioUnit);
        if (status != noErr) {
            return ma_result_from_OSStatus(status);
        }

        formatScope   = (deviceType == ma_device_type_playback) ? kAudioUnitScope_Input : kAudioUnitScope_Output;
        formatElement = (deviceType == ma_device_type_playback) ? MA_COREAUDIO_OUTPUT_BUS : MA_COREAUDIO_INPUT_BUS;

        propSize = sizeof(bestFormat);
        status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, &propSize);
        if (status != noErr) {
            ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(audioUnit);
            return ma_result_from_OSStatus(status);
        }

        ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(audioUnit);
        audioUnit = NULL;

        /* Only a single format is being reported for iOS. */
        pDeviceInfo->nativeDataFormatCount = 1;

        result = ma_format_from_AudioStreamBasicDescription(&bestFormat, &pDeviceInfo->nativeDataFormats[0].format);
        if (result != MA_SUCCESS) {
            return result;
        }

        pDeviceInfo->nativeDataFormats[0].channels = bestFormat.mChannelsPerFrame;

        /*
        It looks like Apple are wanting to push the whole AVAudioSession thing. Thus, we need to use that to determine device settings. To do
        this we just get the shared instance and inspect.
        */
        @autoreleasepool {
            AVAudioSession* pAudioSession = [AVAudioSession sharedInstance];
            MA_ASSERT(pAudioSession != NULL);

            pDeviceInfo->nativeDataFormats[0].sampleRate = (ma_uint32)pAudioSession.sampleRate;
        }
    }
#endif

    (void)pDeviceInfo; /* Unused. */
    return MA_SUCCESS;
}

static AudioBufferList* ma_allocate_AudioBufferList__coreaudio(ma_uint32 sizeInFrames, ma_format format, ma_uint32 channels, ma_stream_layout layout, const ma_allocation_callbacks* pAllocationCallbacks)
{
    AudioBufferList* pBufferList;
    UInt32 audioBufferSizeInBytes;
    size_t allocationSize;

    MA_ASSERT(sizeInFrames > 0);
    MA_ASSERT(format != ma_format_unknown);
    MA_ASSERT(channels > 0);

    allocationSize = sizeof(AudioBufferList) - sizeof(AudioBuffer);  /* Subtract sizeof(AudioBuffer) because that part is dynamically sized. */
    if (layout == ma_stream_layout_interleaved) {
        /* Interleaved case. This is the simple case because we just have one buffer. */
        allocationSize += sizeof(AudioBuffer) * 1;
    } else {
        /* Non-interleaved case. This is the more complex case because there's more than one buffer. */
        allocationSize += sizeof(AudioBuffer) * channels;
    }

    allocationSize += sizeInFrames * ma_get_bytes_per_frame(format, channels);

    pBufferList = (AudioBufferList*)ma_malloc(allocationSize, pAllocationCallbacks);
    if (pBufferList == NULL) {
        return NULL;
    }

    audioBufferSizeInBytes = (UInt32)(sizeInFrames * ma_get_bytes_per_sample(format));

    if (layout == ma_stream_layout_interleaved) {
        pBufferList->mNumberBuffers = 1;
        pBufferList->mBuffers[0].mNumberChannels = channels;
        pBufferList->mBuffers[0].mDataByteSize   = audioBufferSizeInBytes * channels;
        pBufferList->mBuffers[0].mData           = (ma_uint8*)pBufferList + sizeof(AudioBufferList);
    } else {
        ma_uint32 iBuffer;
        pBufferList->mNumberBuffers = channels;
        for (iBuffer = 0; iBuffer < pBufferList->mNumberBuffers; ++iBuffer) {
            pBufferList->mBuffers[iBuffer].mNumberChannels = 1;
            pBufferList->mBuffers[iBuffer].mDataByteSize   = audioBufferSizeInBytes;
            pBufferList->mBuffers[iBuffer].mData           = (ma_uint8*)pBufferList + ((sizeof(AudioBufferList) - sizeof(AudioBuffer)) + (sizeof(AudioBuffer) * channels)) + (audioBufferSizeInBytes * iBuffer);
        }
    }

    return pBufferList;
}

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN

                    ma_uint32 framesToSend = sizeof(silentBuffer) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
                    if (framesToSend > framesRemaining) {
                        framesToSend = framesRemaining;
                    }

                    ma_device_handle_backend_data_callback(pDevice, NULL, silentBuffer, framesToSend);

                    framesRemaining -= framesToSend;
                }

                /*ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "  WARNING: Outputting silence. frameCount=%d, mNumberChannels=%d, mDataByteSize=%d\n", (int)frameCount, (int)pRenderedBufferList->mBuffers[iBuffer].mNumberChannels, (int)...
            }
        }
    } else {
        /* This is the deinterleaved case. We need to interleave the audio data before sending it to the client. This assumes each buffer is the same size. */
        MA_ASSERT(pDevice->capture.internalChannels <= MA_MAX_CHANNELS);    /* This should have been validated at initialization time. */

        /*
        For safety we'll check that the internal channels is a multiple of the buffer count. If it's not it means something
        very strange has happened and we're not going to support it.
        */
        if ((pRenderedBufferList->mNumberBuffers % pDevice->capture.internalChannels) == 0) {
            ma_uint8 tempBuffer[4096];
            for (iBuffer = 0; iBuffer < pRenderedBufferList->mNumberBuffers; iBuffer += pDevice->capture.internalChannels) {
                ma_uint32 framesRemaining = frameCount;
                while (framesRemaining > 0) {
                    void* ppDeinterleavedBuffers[MA_MAX_CHANNELS];
                    ma_uint32 iChannel;
                    ma_uint32 framesToSend = sizeof(tempBuffer) / ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
                    if (framesToSend > framesRemaining) {
                        framesToSend = framesRemaining;
                    }

                    for (iChannel = 0; iChannel < pDevice->capture.internalChannels; ++iChannel) {
                        ppDeinterleavedBuffers[iChannel] = (void*)ma_offset_ptr(pRenderedBufferList->mBuffers[iBuffer+iChannel].mData, (frameCount - framesRemaining) * ma_get_bytes_per_sample(pDevice->capture.internalFormat));
                    }

                    ma_interleave_pcm_frames(pDevice->capture.internalFormat, pDevice->capture.internalChannels, framesToSend, (const void**)ppDeinterleavedBuffers, tempBuffer);
                    ma_device_handle_backend_data_callback(pDevice, NULL, tempBuffer, framesToSend);

                    framesRemaining -= framesToSend;
                }
            }
        }
    }

    (void)pActionFlags;
    (void)pTimeStamp;
    (void)busNumber;
    (void)frameCount;
    (void)pUnusedBufferList;

    return noErr;
}

static void on_start_stop__coreaudio(void* pUserData, AudioUnit audioUnit, AudioUnitPropertyID propertyID, AudioUnitScope scope, AudioUnitElement element)
{
    ma_device* pDevice = (ma_device*)pUserData;
    MA_ASSERT(pDevice != NULL);

    /* Don't do anything if it looks like we're just reinitializing due to a device switch. */
    if (((audioUnit == pDevice->coreaudio.audioUnitPlayback) && pDevice->coreaudio.isSwitchingPlaybackDevice) ||
        ((audioUnit == pDevice->coreaudio.audioUnitCapture)  && pDevice->coreaudio.isSwitchingCaptureDevice)) {
        return;
    }

    /*
    There's been a report of a deadlock here when triggered by ma_device_uninit(). It looks like
    AudioUnitGetProprty (called below) and AudioComponentInstanceDispose (called in ma_device_uninit)
    can try waiting on the same lock. I'm going to try working around this by not calling any Core
    Audio APIs in the callback when the device has been stopped or uninitialized.
    */
    if (ma_device_get_state(pDevice) == ma_device_state_uninitialized || ma_device_get_state(pDevice) == ma_device_state_stopping || ma_device_get_state(pDevice) == ma_device_state_stopped) {
        ma_device__on_notification_stopped(pDevice);
    } else {
        UInt32 isRunning;
        UInt32 isRunningSize = sizeof(isRunning);
        OSStatus status = ((ma_AudioUnitGetProperty_proc)pDevice->pContext->coreaudio.AudioUnitGetProperty)(audioUnit, kAudioOutputUnitProperty_IsRunning, scope, element, &isRunning, &isRunningSize);
        if (status != noErr) {
            goto done; /* Don't really know what to do in this case... just ignore it, I suppose... */
        }

        if (!isRunning) {
            /*
            The stop event is a bit annoying in Core Audio because it will be called when we automatically switch the default device. Some scenarios to consider:

            1) When the device is unplugged, this will be called _before_ the default device change notification.
            2) When the device is changed via the default device change notification, this will be called _after_ the switch.

            For case #1, we just check if there's a new default device available. If so, we just ignore the stop event. For case #2 we check a flag.
            */
            if (((audioUnit == pDevice->coreaudio.audioUnitPlayback) && pDevice->coreaudio.isDefaultPlaybackDevice) ||
                ((audioUnit == pDevice->coreaudio.audioUnitCapture)  && pDevice->coreaudio.isDefaultCaptureDevice)) {
                /*
                It looks like the device is switching through an external event, such as the user unplugging the device or changing the default device
                via the operating system's sound settings. If we're re-initializing the device, we just terminate because we want the stopping of the
                device to be seamless to the client (we don't want them receiving the stopped event and thinking that the device has stopped when it
                hasn't!).
                */
                if (((audioUnit == pDevice->coreaudio.audioUnitPlayback) && pDevice->coreaudio.isSwitchingPlaybackDevice) ||
                    ((audioUnit == pDevice->coreaudio.audioUnitCapture)  && pDevice->coreaudio.isSwitchingCaptureDevice)) {
                    goto done;
                }

                /*
                Getting here means the device is not reinitializing which means it may have been unplugged. From what I can see, it looks like Core Audio
                will try switching to the new default device seamlessly. We need to somehow find a way to determine whether or not Core Audio will most
                likely be successful in switching to the new device.

                TODO: Try to predict if Core Audio will switch devices. If not, the stopped callback needs to be posted.
                */
                goto done;
            }

            /* Getting here means we need to stop the device. */
            ma_device__on_notification_stopped(pDevice);
        }
    }

    (void)propertyID; /* Unused. */

done:
    /* Always signal the stop event. It's possible for the "else" case to get hit which can happen during an interruption. */
    ma_event_signal(&pDevice->coreaudio.stopEvent);
}

#if defined(MA_APPLE_DESKTOP)
static ma_spinlock g_DeviceTrackingInitLock_CoreAudio = 0;  /* A spinlock for mutal exclusion of the init/uninit of the global tracking data. Initialization to 0 is what we need. */
static ma_uint32   g_DeviceTrackingInitCounter_CoreAudio = 0;
static ma_mutex    g_DeviceTrackingMutex_CoreAudio;
static ma_device** g_ppTrackedDevices_CoreAudio = NULL;
static ma_uint32   g_TrackedDeviceCap_CoreAudio = 0;
static ma_uint32   g_TrackedDeviceCount_CoreAudio = 0;

static OSStatus ma_default_device_changed__coreaudio(AudioObjectID objectID, UInt32 addressCount, const AudioObjectPropertyAddress* pAddresses, void* pUserData)
{
    ma_device_type deviceType;

    /* Not sure if I really need to check this, but it makes me feel better. */
    if (addressCount == 0) {
        return noErr;
    }

    if (pAddresses[0].mSelector == kAudioHardwarePropertyDefaultOutputDevice) {
        deviceType = ma_device_type_playback;
    } else if (pAddresses[0].mSelector == kAudioHardwarePropertyDefaultInputDevice) {
        deviceType = ma_device_type_capture;
    } else {
        return noErr;   /* Should never hit this. */
    }

    ma_mutex_lock(&g_DeviceTrackingMutex_CoreAudio);
    {
        ma_uint32 iDevice;
        for (iDevice = 0; iDevice < g_TrackedDeviceCount_CoreAudio; iDevice += 1) {
            ma_result reinitResult;
            ma_device* pDevice;

            pDevice = g_ppTrackedDevices_CoreAudio[iDevice];
            if (pDevice->type == deviceType || pDevice->type == ma_device_type_duplex) {
                if (deviceType == ma_device_type_playback) {
                    pDevice->coreaudio.isSwitchingPlaybackDevice = MA_TRUE;
                    reinitResult = ma_device_reinit_internal__coreaudio(pDevice, deviceType, MA_TRUE);
                    pDevice->coreaudio.isSwitchingPlaybackDevice = MA_FALSE;
                } else {
                    pDevice->coreaudio.isSwitchingCaptureDevice = MA_TRUE;

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN

#endif
    pData->component = NULL;
    pData->audioUnit = NULL;
    pData->pAudioBufferList = NULL;

#if defined(MA_APPLE_DESKTOP)
    result = ma_find_AudioObjectID(pContext, deviceType, pDeviceID, &deviceObjectID);
    if (result != MA_SUCCESS) {
        return result;
    }

    pData->deviceObjectID = deviceObjectID;
#endif

    /* Core audio doesn't really use the notion of a period so we can leave this unmodified, but not too over the top. */
    pData->periodsOut = pData->periodsIn;
    if (pData->periodsOut == 0) {
        pData->periodsOut = MA_DEFAULT_PERIODS;
    }
    if (pData->periodsOut > 16) {
        pData->periodsOut = 16;
    }


    /* Audio unit. */
    status = ((ma_AudioComponentInstanceNew_proc)pContext->coreaudio.AudioComponentInstanceNew)((AudioComponent)pContext->coreaudio.component, (AudioUnit*)&pData->audioUnit);
    if (status != noErr) {
        return ma_result_from_OSStatus(status);
    }


    /* The input/output buses need to be explicitly enabled and disabled. We set the flag based on the output unit first, then we just swap it for input. */
    enableIOFlag = 1;
    if (deviceType == ma_device_type_capture) {
        enableIOFlag = 0;
    }

    status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, MA_COREAUDIO_OUTPUT_BUS, &enableIOFlag, sizeof(enableIOFlag));
    if (status != noErr) {
        ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
        return ma_result_from_OSStatus(status);
    }

    enableIOFlag = (enableIOFlag == 0) ? 1 : 0;
    status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, MA_COREAUDIO_INPUT_BUS, &enableIOFlag, sizeof(enableIOFlag));
    if (status != noErr) {
        ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
        return ma_result_from_OSStatus(status);
    }


    /* Set the device to use with this audio unit. This is only used on desktop since we are using defaults on mobile. */
#if defined(MA_APPLE_DESKTOP)
    status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &deviceObjectID, sizeof(deviceObjectID));
    if (status != noErr) {
        ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
        return ma_result_from_OSStatus(result);
    }
#else
    /*
    For some reason it looks like Apple is only allowing selection of the input device. There does not appear to be any way to change
    the default output route. I have no idea why this is like this, but for now we'll only be able to configure capture devices.
    */
    if (pDeviceID != NULL) {
        if (deviceType == ma_device_type_capture) {
            ma_bool32 found = MA_FALSE;
            NSArray *pInputs = [[[AVAudioSession sharedInstance] currentRoute] inputs];
            for (AVAudioSessionPortDescription* pPortDesc in pInputs) {
                if (strcmp(pDeviceID->coreaudio, [pPortDesc.UID UTF8String]) == 0) {
                    [[AVAudioSession sharedInstance] setPreferredInput:pPortDesc error:nil];
                    found = MA_TRUE;
                    break;
                }
            }

            if (found == MA_FALSE) {
                return MA_DOES_NOT_EXIST;
            }
        }
    }
#endif

    /*
    Format. This is the hardest part of initialization because there's a few variables to take into account.
      1) The format must be supported by the device.
      2) The format must be supported miniaudio.
      3) There's a priority that miniaudio prefers.

    Ideally we would like to use a format that's as close to the hardware as possible so we can get as close to a passthrough as possible. The
    most important property is the sample rate. miniaudio can do format conversion for any sample rate and channel count, but cannot do the same
    for the sample data format. If the sample data format is not supported by miniaudio it must be ignored completely.

    On mobile platforms this is a bit different. We just force the use of whatever the audio unit's current format is set to.
    */
    {
        AudioStreamBasicDescription origFormat;
        UInt32 origFormatSize = sizeof(origFormat);
        AudioUnitScope   formatScope   = (deviceType == ma_device_type_playback) ? kAudioUnitScope_Input : kAudioUnitScope_Output;
        AudioUnitElement formatElement = (deviceType == ma_device_type_playback) ? MA_COREAUDIO_OUTPUT_BUS : MA_COREAUDIO_INPUT_BUS;

        if (deviceType == ma_device_type_playback) {
            status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, MA_COREAUDIO_OUTPUT_BUS, &origFormat, &origFormatSize);
        } else {
            status = ((ma_AudioUnitGetProperty_proc)pContext->coreaudio.AudioUnitGetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, MA_COREAUDIO_INPUT_BUS, &origFormat, &origFormatSize);
        }
        if (status != noErr) {
            ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
            return ma_result_from_OSStatus(status);
        }

    #if defined(MA_APPLE_DESKTOP)
        result = ma_find_best_format__coreaudio(pContext, deviceObjectID, deviceType, pData->formatIn, pData->channelsIn, pData->sampleRateIn, &origFormat, &bestFormat);
        if (result != MA_SUCCESS) {
            ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
            return result;
        }

        /*
        Technical Note TN2091: Device input using the HAL Output Audio Unit
            https://developer.apple.com/library/archive/technotes/tn2091/_index.html

        This documentation says the following:

            The internal AudioConverter can handle any *simple* conversion. Typically, this means that a client can specify ANY
            variant of the PCM formats. Consequently, the device's sample rate should match the desired sample rate. If sample rate
            conversion is needed, it can be accomplished by buffering the input and converting the data on a separate thread with
            another AudioConverter.

        The important part here is the mention that it can handle *simple* conversions, which does *not* include sample rate. We
        therefore want to ensure the sample rate stays consistent. This document is specifically for input, but I'm going to play it
        safe and apply the same rule to output as well.

        I have tried going against the documentation by setting the sample rate anyway, but this just results in AudioUnitRender()
        returning a result code of -10863. I have also tried changing the format directly on the input scope on the input bus, but
        this just results in `ca_require: IsStreamFormatWritable(inScope, inElement) NotWritable` when trying to set the format.

        Something that does seem to work, however, has been setting the nominal sample rate on the deivce object. The problem with
        this, however, is that it actually changes the sample rate at the operating system level and not just the application. This
        could be intrusive to the user, however, so I don't think it's wise to make this the default. Instead I'm making this a
        configuration option. When the `coreaudio.allowNominalSampleRateChange` config option is set to true, changing the sample
        rate will be allowed. Otherwise it'll be fixed to the current sample rate. To check the system-defined sample rate, run
        the Audio MIDI Setup program that comes installed on macOS and observe how the sample rate changes as the sample rate is
        changed by miniaudio.
        */
        if (pData->allowNominalSampleRateChange) {
            AudioValueRange sampleRateRange;
            AudioObjectPropertyAddress propAddress;

            sampleRateRange.mMinimum = bestFormat.mSampleRate;
            sampleRateRange.mMaximum = bestFormat.mSampleRate;

            propAddress.mSelector = kAudioDevicePropertyNominalSampleRate;
            propAddress.mScope    = (deviceType == ma_device_type_playback) ? kAudioObjectPropertyScopeOutput : kAudioObjectPropertyScopeInput;
            propAddress.mElement  = kAudioObjectPropertyElementMaster;

            status = ((ma_AudioObjectSetPropertyData_proc)pContext->coreaudio.AudioObjectSetPropertyData)(deviceObjectID, &propAddress, 0, NULL, sizeof(sampleRateRange), &sampleRateRange);
            if (status != noErr) {
                bestFormat.mSampleRate = origFormat.mSampleRate;
            }
        } else {
            bestFormat.mSampleRate = origFormat.mSampleRate;
        }

        status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, sizeof(bestFormat));
        if (status != noErr) {
            /* We failed to set the format, so fall back to the current format of the audio unit. */
            bestFormat = origFormat;
        }
    #else
        bestFormat = origFormat;

        /*
        Sample rate is a little different here because for some reason kAudioUnitProperty_StreamFormat returns 0... Oh well. We need to instead try
        setting the sample rate to what the user has requested and then just see the results of it. Need to use some Objective-C here for this since
        it depends on Apple's AVAudioSession API. To do this we just get the shared AVAudioSession instance and then set it. Note that from what I
        can tell, it looks like the sample rate is shared between playback and capture for everything.
        */
        @autoreleasepool {
            AVAudioSession* pAudioSession = [AVAudioSession sharedInstance];
            MA_ASSERT(pAudioSession != NULL);

            [pAudioSession setPreferredSampleRate:(double)pData->sampleRateIn error:nil];
            bestFormat.mSampleRate = pAudioSession.sampleRate;

            /*
            I've had a report that the channel count returned by AudioUnitGetProperty above is inconsistent with
            AVAudioSession outputNumberOfChannels. I'm going to try using the AVAudioSession values instead.
            */
            if (deviceType == ma_device_type_playback) {
                bestFormat.mChannelsPerFrame = (UInt32)pAudioSession.outputNumberOfChannels;
            }
            if (deviceType == ma_device_type_capture) {
                bestFormat.mChannelsPerFrame = (UInt32)pAudioSession.inputNumberOfChannels;
            }
        }

        status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, sizeof(bestFormat));
        if (status != noErr) {
            ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
            return ma_result_from_OSStatus(status);
        }
    #endif

        result = ma_format_from_AudioStreamBasicDescription(&bestFormat, &pData->formatOut);
        if (result != MA_SUCCESS) {
            ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
            return result;
        }

        if (pData->formatOut == ma_format_unknown) {
            ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit);
            return MA_FORMAT_NOT_SUPPORTED;
        }

        pData->channelsOut   = bestFormat.mChannelsPerFrame;
        pData->sampleRateOut = bestFormat.mSampleRate;
    }

    /* Clamp the channel count for safety. */
    if (pData->channelsOut > MA_MAX_CHANNELS) {
        pData->channelsOut = MA_MAX_CHANNELS;
    }

    /*
    Internal channel map. This is weird in my testing. If I use the AudioObject to get the
    channel map, the channel descriptions are set to "Unknown" for some reason. To work around
    this it looks like retrieving it from the AudioUnit will work. However, and this is where
    it gets weird, it doesn't seem to work with capture devices, nor at all on iOS... Therefore
    I'm going to fall back to a default assumption in these cases.
    */
#if defined(MA_APPLE_DESKTOP)
    result = ma_get_AudioUnit_channel_map(pContext, pData->audioUnit, deviceType, pData->channelMapOut, pData->channelsOut);
    if (result != MA_SUCCESS) {
    #if 0
        /* Try falling back to the channel map from the AudioObject. */
        result = ma_get_AudioObject_channel_map(pContext, deviceObjectID, deviceType, pData->channelMapOut, pData->channelsOut);
        if (result != MA_SUCCESS) {
            return result;
        }
    #else
        /* Fall back to default assumptions. */
        ma_channel_map_init_standard(ma_standard_channel_map_default, pData->channelMapOut, ma_countof(pData->channelMapOut), pData->channelsOut);
    #endif
    }
#else
    /* TODO: Figure out how to get the channel map using AVAudioSession. */
    ma_channel_map_init_standard(ma_standard_channel_map_default, pData->channelMapOut, ma_countof(pData->channelMapOut), pData->channelsOut);
#endif


    /* Buffer size. Not allowing this to be configurable on iOS. */
    if (pData->periodSizeInFramesIn == 0) {
        if (pData->periodSizeInMillisecondsIn == 0) {
            if (pData->performanceProfile == ma_performance_profile_low_latency) {
                actualPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_LOW_LATENCY, pData->sampleRateOut);
            } else {
                actualPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(MA_DEFAULT_PERIOD_SIZE_IN_MILLISECONDS_CONSERVATIVE, pData->sampleRateOut);
            }
        } else {
            actualPeriodSizeInFrames = ma_calculate_buffer_size_in_frames_from_milliseconds(pData->periodSizeInMillisecondsIn, pData->sampleRateOut);
        }
    } else {
        actualPeriodSizeInFrames = pData->periodSizeInFramesIn;
    }

#if defined(MA_APPLE_DESKTOP)
    result = ma_set_AudioObject_buffer_size_in_frames(pContext, deviceObjectID, deviceType, &actualPeriodSizeInFrames);
    if (result != MA_SUCCESS) {
        return result;
    }
#else
    /*
    On iOS, the size of the IO buffer needs to be specified in seconds and is a floating point
    number. I don't trust any potential truncation errors due to converting from float to integer
    so I'm going to explicitly set the actual period size to the next power of 2.
    */
    @autoreleasepool {
        AVAudioSession* pAudioSession = [AVAudioSession sharedInstance];
        MA_ASSERT(pAudioSession != NULL);
        
        [pAudioSession setPreferredIOBufferDuration:((float)actualPeriodSizeInFrames / pAudioSession.sampleRate) error:nil];
        actualPeriodSizeInFrames = ma_next_power_of_2((ma_uint32)(pAudioSession.IOBufferDuration * pAudioSession.sampleRate));
    }
#endif


    /*

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN

            we'll try Playback and if that fails we'll try record. If all of these fail we'll just not set the category.
            */
        #if !defined(MA_APPLE_TV) && !defined(MA_APPLE_WATCH)
            options |= AVAudioSessionCategoryOptionDefaultToSpeaker;
        #endif

            if ([pAudioSession setCategory: AVAudioSessionCategoryPlayAndRecord withOptions:options error:nil]) {
                /* Using PlayAndRecord */
            } else if ([pAudioSession setCategory: AVAudioSessionCategoryPlayback withOptions:options error:nil]) {
                /* Using Playback */
            } else if ([pAudioSession setCategory: AVAudioSessionCategoryRecord withOptions:options error:nil]) {
                /* Using Record */
            } else {
                /* Leave as default? */
            }
        } else {
            if (pConfig->coreaudio.sessionCategory != ma_ios_session_category_none) {
            #if defined(__IPHONE_12_0)
                if (![pAudioSession setCategory: ma_to_AVAudioSessionCategory(pConfig->coreaudio.sessionCategory) withOptions:options error:nil]) {
                    return MA_INVALID_OPERATION;    /* Failed to set session category. */
                }
            #else
                /* Ignore the session category on version 11 and older, but post a warning. */
                ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_WARNING, "Session category only supported in iOS 12 and newer.");
            #endif
            }
        }

        if (!pConfig->coreaudio.noAudioSessionActivate) {
            if (![pAudioSession setActive:true error:nil]) {
                ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "Failed to activate audio session.");
                return MA_FAILED_TO_INIT_BACKEND;
            }
        }
    }
#endif

#if !defined(MA_NO_RUNTIME_LINKING) && !defined(MA_APPLE_MOBILE)
    pContext->coreaudio.hCoreFoundation = ma_dlopen(pContext, "CoreFoundation.framework/CoreFoundation");
    if (pContext->coreaudio.hCoreFoundation == NULL) {
        return MA_API_NOT_FOUND;
    }

    pContext->coreaudio.CFStringGetCString = ma_dlsym(pContext, pContext->coreaudio.hCoreFoundation, "CFStringGetCString");
    pContext->coreaudio.CFRelease          = ma_dlsym(pContext, pContext->coreaudio.hCoreFoundation, "CFRelease");


    pContext->coreaudio.hCoreAudio = ma_dlopen(pContext, "CoreAudio.framework/CoreAudio");
    if (pContext->coreaudio.hCoreAudio == NULL) {
        ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
        return MA_API_NOT_FOUND;
    }

    pContext->coreaudio.AudioObjectGetPropertyData        = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectGetPropertyData");
    pContext->coreaudio.AudioObjectGetPropertyDataSize    = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectGetPropertyDataSize");
    pContext->coreaudio.AudioObjectSetPropertyData        = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectSetPropertyData");
    pContext->coreaudio.AudioObjectAddPropertyListener    = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectAddPropertyListener");
    pContext->coreaudio.AudioObjectRemovePropertyListener = ma_dlsym(pContext, pContext->coreaudio.hCoreAudio, "AudioObjectRemovePropertyListener");

    /*
    It looks like Apple has moved some APIs from AudioUnit into AudioToolbox on more recent versions of macOS. They are still
    defined in AudioUnit, but just in case they decide to remove them from there entirely I'm going to implement a fallback.
    The way it'll work is that it'll first try AudioUnit, and if the required symbols are not present there we'll fall back to
    AudioToolbox.
    */
    pContext->coreaudio.hAudioUnit = ma_dlopen(pContext, "AudioUnit.framework/AudioUnit");
    if (pContext->coreaudio.hAudioUnit == NULL) {
        ma_dlclose(pContext, pContext->coreaudio.hCoreAudio);
        ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
        return MA_API_NOT_FOUND;
    }

    if (ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentFindNext") == NULL) {
        /* Couldn't find the required symbols in AudioUnit, so fall back to AudioToolbox. */
        ma_dlclose(pContext, pContext->coreaudio.hAudioUnit);
        pContext->coreaudio.hAudioUnit = ma_dlopen(pContext, "AudioToolbox.framework/AudioToolbox");
        if (pContext->coreaudio.hAudioUnit == NULL) {
            ma_dlclose(pContext, pContext->coreaudio.hCoreAudio);
            ma_dlclose(pContext, pContext->coreaudio.hCoreFoundation);
            return MA_API_NOT_FOUND;
        }
    }

    pContext->coreaudio.AudioComponentFindNext            = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentFindNext");
    pContext->coreaudio.AudioComponentInstanceDispose     = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentInstanceDispose");
    pContext->coreaudio.AudioComponentInstanceNew         = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioComponentInstanceNew");
    pContext->coreaudio.AudioOutputUnitStart              = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioOutputUnitStart");
    pContext->coreaudio.AudioOutputUnitStop               = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioOutputUnitStop");
    pContext->coreaudio.AudioUnitAddPropertyListener      = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitAddPropertyListener");
    pContext->coreaudio.AudioUnitGetPropertyInfo          = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitGetPropertyInfo");
    pContext->coreaudio.AudioUnitGetProperty              = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitGetProperty");
    pContext->coreaudio.AudioUnitSetProperty              = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitSetProperty");
    pContext->coreaudio.AudioUnitInitialize               = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitInitialize");
    pContext->coreaudio.AudioUnitRender                   = ma_dlsym(pContext, pContext->coreaudio.hAudioUnit, "AudioUnitRender");
#else
    pContext->coreaudio.CFStringGetCString                = (ma_proc)CFStringGetCString;
    pContext->coreaudio.CFRelease                         = (ma_proc)CFRelease;

    #if defined(MA_APPLE_DESKTOP)
    pContext->coreaudio.AudioObjectGetPropertyData        = (ma_proc)AudioObjectGetPropertyData;
    pContext->coreaudio.AudioObjectGetPropertyDataSize    = (ma_proc)AudioObjectGetPropertyDataSize;
    pContext->coreaudio.AudioObjectSetPropertyData        = (ma_proc)AudioObjectSetPropertyData;
    pContext->coreaudio.AudioObjectAddPropertyListener    = (ma_proc)AudioObjectAddPropertyListener;
    pContext->coreaudio.AudioObjectRemovePropertyListener = (ma_proc)AudioObjectRemovePropertyListener;
    #endif

    pContext->coreaudio.AudioComponentFindNext            = (ma_proc)AudioComponentFindNext;
    pContext->coreaudio.AudioComponentInstanceDispose     = (ma_proc)AudioComponentInstanceDispose;
    pContext->coreaudio.AudioComponentInstanceNew         = (ma_proc)AudioComponentInstanceNew;
    pContext->coreaudio.AudioOutputUnitStart              = (ma_proc)AudioOutputUnitStart;
    pContext->coreaudio.AudioOutputUnitStop               = (ma_proc)AudioOutputUnitStop;
    pContext->coreaudio.AudioUnitAddPropertyListener      = (ma_proc)AudioUnitAddPropertyListener;
    pContext->coreaudio.AudioUnitGetPropertyInfo          = (ma_proc)AudioUnitGetPropertyInfo;
    pContext->coreaudio.AudioUnitGetProperty              = (ma_proc)AudioUnitGetProperty;
    pContext->coreaudio.AudioUnitSetProperty              = (ma_proc)AudioUnitSetProperty;
    pContext->coreaudio.AudioUnitInitialize               = (ma_proc)AudioUnitInitialize;
    pContext->coreaudio.AudioUnitRender                   = (ma_proc)AudioUnitRender;
#endif

    /* Audio component. */
    {

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN


    goto return_detailed_info;
#else
    goto return_default_device;
#endif

return_default_device:
    if (pDeviceID != NULL) {
        if ((deviceType == ma_device_type_playback && pDeviceID->opensl != SL_DEFAULTDEVICEID_AUDIOOUTPUT) ||
            (deviceType == ma_device_type_capture  && pDeviceID->opensl != SL_DEFAULTDEVICEID_AUDIOINPUT)) {
            return MA_NO_DEVICE;   /* Don't know the device. */
        }
    }

    /* ID and Name / Description */
    if (deviceType == ma_device_type_playback) {
        pDeviceInfo->id.opensl = SL_DEFAULTDEVICEID_AUDIOOUTPUT;
        ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1);
    } else {
        pDeviceInfo->id.opensl = SL_DEFAULTDEVICEID_AUDIOINPUT;
        ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1);
    }

    pDeviceInfo->isDefault = MA_TRUE;

    goto return_detailed_info;


return_detailed_info:

    /*
    For now we're just outputting a set of values that are supported by the API but not necessarily supported
    by the device natively. Later on we should work on this so that it more closely reflects the device's
    actual native format.
    */
    pDeviceInfo->nativeDataFormatCount = 0;
#if defined(MA_ANDROID) && __ANDROID_API__ >= 21
    ma_context_add_data_format__opensl(pContext, ma_format_f32, pDeviceInfo);
#endif
    ma_context_add_data_format__opensl(pContext, ma_format_s16, pDeviceInfo);
    ma_context_add_data_format__opensl(pContext, ma_format_u8,  pDeviceInfo);

    return MA_SUCCESS;
}


#ifdef MA_ANDROID
/*void ma_buffer_queue_callback_capture__opensl_android(SLAndroidSimpleBufferQueueItf pBufferQueue, SLuint32 eventFlags, const void* pBuffer, SLuint32 bufferSize, SLuint32 dataUsed, void* pContext)*/
static void ma_buffer_queue_callback_capture__opensl_android(SLAndroidSimpleBufferQueueItf pBufferQueue, void* pUserData)
{
    ma_device* pDevice = (ma_device*)pUserData;
    size_t periodSizeInBytes;
    ma_uint8* pBuffer;
    SLresult resultSL;

    MA_ASSERT(pDevice != NULL);

    (void)pBufferQueue;

    /*
    For now, don't do anything unless the buffer was fully processed. From what I can tell, it looks like
    OpenSL|ES 1.1 improves on buffer queues to the point that we could much more intelligently handle this,
    but unfortunately it looks like Android is only supporting OpenSL|ES 1.0.1 for now :(
    */

    /* Don't do anything if the device is not started. */
    if (ma_device_get_state(pDevice) != ma_device_state_started) {
        return;
    }

    /* Don't do anything if the device is being drained. */
    if (pDevice->opensl.isDrainingCapture) {
        return;
    }

    periodSizeInBytes = pDevice->capture.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->capture.internalFormat, pDevice->capture.internalChannels);
    pBuffer = pDevice->opensl.pBufferCapture + (pDevice->opensl.currentBufferIndexCapture * periodSizeInBytes);

    ma_device_handle_backend_data_callback(pDevice, NULL, pBuffer, pDevice->capture.internalPeriodSizeInFrames);

    resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueueCapture)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueueCapture, pBuffer, periodSizeInBytes);
    if (resultSL != SL_RESULT_SUCCESS) {
        return;
    }

    pDevice->opensl.currentBufferIndexCapture = (pDevice->opensl.currentBufferIndexCapture + 1) % pDevice->capture.internalPeriods;
}

static void ma_buffer_queue_callback_playback__opensl_android(SLAndroidSimpleBufferQueueItf pBufferQueue, void* pUserData)
{
    ma_device* pDevice = (ma_device*)pUserData;
    size_t periodSizeInBytes;
    ma_uint8* pBuffer;
    SLresult resultSL;

    MA_ASSERT(pDevice != NULL);

    (void)pBufferQueue;

    /* Don't do anything if the device is not started. */
    if (ma_device_get_state(pDevice) != ma_device_state_started) {
        return;
    }

    /* Don't do anything if the device is being drained. */
    if (pDevice->opensl.isDrainingPlayback) {
        return;
    }

    periodSizeInBytes = pDevice->playback.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
    pBuffer = pDevice->opensl.pBufferPlayback + (pDevice->opensl.currentBufferIndexPlayback * periodSizeInBytes);

    ma_device_handle_backend_data_callback(pDevice, pBuffer, NULL, pDevice->playback.internalPeriodSizeInFrames);

    resultSL = MA_OPENSL_BUFFERQUEUE(pDevice->opensl.pBufferQueuePlayback)->Enqueue((SLAndroidSimpleBufferQueueItf)pDevice->opensl.pBufferQueuePlayback, pBuffer, periodSizeInBytes);
    if (resultSL != SL_RESULT_SUCCESS) {
        return;
    }

    pDevice->opensl.currentBufferIndexPlayback = (pDevice->opensl.currentBufferIndexPlayback + 1) % pDevice->playback.internalPeriods;
}
#endif

share/public_html/static/music_worklet_inprogress/decoder/deps/miniaudio/miniaudio.h  view on Meta::CPAN


MA_API ma_result ma_hishelf2_reinit(const ma_hishelf2_config* pConfig, ma_hishelf2* pFilter)
{
    ma_result result;
    ma_biquad_config bqConfig;

    if (pFilter == NULL || pConfig == NULL) {
        return MA_INVALID_ARGS;
    }

    bqConfig = ma_hishelf2__get_biquad_config(pConfig);
    result = ma_biquad_reinit(&bqConfig, &pFilter->bq);
    if (result != MA_SUCCESS) {
        return result;
    }

    return MA_SUCCESS;
}

static MA_INLINE void ma_hishelf2_process_pcm_frame_s16(ma_hishelf2* pFilter, ma_int16* pFrameOut, const ma_int16* pFrameIn)
{
    ma_biquad_process_pcm_frame_s16(&pFilter->bq, pFrameOut, pFrameIn);
}

static MA_INLINE void ma_hishelf2_process_pcm_frame_f32(ma_hishelf2* pFilter, float* pFrameOut, const float* pFrameIn)
{
    ma_biquad_process_pcm_frame_f32(&pFilter->bq, pFrameOut, pFrameIn);
}

MA_API ma_result ma_hishelf2_process_pcm_frames(ma_hishelf2* pFilter, void* pFramesOut, const void* pFramesIn, ma_uint64 frameCount)
{
    if (pFilter == NULL) {
        return MA_INVALID_ARGS;
    }

    return ma_biquad_process_pcm_frames(&pFilter->bq, pFramesOut, pFramesIn, frameCount);
}

MA_API ma_uint32 ma_hishelf2_get_latency(const ma_hishelf2* pFilter)
{
    if (pFilter == NULL) {
        return 0;
    }

    return ma_biquad_get_latency(&pFilter->bq);
}



/*
Delay
*/
MA_API ma_delay_config ma_delay_config_init(ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 delayInFrames, float decay)
{
    ma_delay_config config;

    MA_ZERO_OBJECT(&config);
    config.channels      = channels;
    config.sampleRate    = sampleRate;
    config.delayInFrames = delayInFrames;
    config.delayStart    = (decay == 0) ? MA_TRUE : MA_FALSE;   /* Delay the start if it looks like we're not configuring an echo. */
    config.wet           = 1;
    config.dry           = 1;
    config.decay         = decay;

    return config;
}


MA_API ma_result ma_delay_init(const ma_delay_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_delay* pDelay)
{
    if (pDelay == NULL) {
        return MA_INVALID_ARGS;
    }

    MA_ZERO_OBJECT(pDelay);

    if (pConfig == NULL) {
        return MA_INVALID_ARGS;
    }

    if (pConfig->decay < 0 || pConfig->decay > 1) {
        return MA_INVALID_ARGS;
    }

    pDelay->config             = *pConfig;
    pDelay->bufferSizeInFrames = pConfig->delayInFrames;
    pDelay->cursor             = 0;

    pDelay->pBuffer = (float*)ma_malloc((size_t)(pDelay->bufferSizeInFrames * ma_get_bytes_per_frame(ma_format_f32, pConfig->channels)), pAllocationCallbacks);
    if (pDelay->pBuffer == NULL) {
        return MA_OUT_OF_MEMORY;
    }

    ma_silence_pcm_frames(pDelay->pBuffer, pDelay->bufferSizeInFrames, ma_format_f32, pConfig->channels);

    return MA_SUCCESS;
}

MA_API void ma_delay_uninit(ma_delay* pDelay, const ma_allocation_callbacks* pAllocationCallbacks)
{
    if (pDelay == NULL) {
        return;
    }

    ma_free(pDelay->pBuffer, pAllocationCallbacks);
}

MA_API ma_result ma_delay_process_pcm_frames(ma_delay* pDelay, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount)
{
    ma_uint32 iFrame;
    ma_uint32 iChannel;
    float* pFramesOutF32 = (float*)pFramesOut;
    const float* pFramesInF32 = (const float*)pFramesIn;

    if (pDelay == NULL || pFramesOut == NULL || pFramesIn == NULL) {
        return MA_INVALID_ARGS;
    }

    for (iFrame = 0; iFrame < frameCount; iFrame += 1) {
        for (iChannel = 0; iChannel < pDelay->config.channels; iChannel += 1) {



( run in 2.857 seconds using v1.01-cache-2.11-cpan-0bb4e1dffa6 )