App-MHFS

 view release on metacpan or  search on metacpan

share/public_html/static/music_worklet_inprogress/decoder/src/mhfs_cl_track.h  view on Meta::CPAN

typedef float float32_t;

typedef enum {
    MHFS_CL_TRACK_M_AUDIOINFO = 0,
    MHFS_CL_TRACK_M_TAGS = 1,
    MHFS_CL_TRACK_M_PICTURE = 2
} mhfs_cl_track_meta;

typedef enum {
    MCT_MAI_FLD_EMPTY         = 0,
    MCT_MAI_FLD_BITSPERSAMPLE = 1 << 0,
    MCT_MAI_FLD_BITRATE       = 1 << 1
} mhfs_cl_track_meta_audioinfo_field;

typedef struct {
    uint64_t totalPCMFrameCount;
    uint32_t sampleRate;
    mhfs_cl_track_meta_audioinfo_field fields;
    uint16_t bitrate;
    uint8_t channels;
    uint8_t bitsPerSample;
} mhfs_cl_track_meta_audioinfo;

typedef struct {
    uint32_t commentSize;
    const uint8_t *comment;
} mhfs_cl_track_meta_tags_comment;

typedef struct {
    uint32_t vendorLength;
    const char *vendorString;
    const uint32_t commentCount;
    drflac_vorbis_comment_iterator comment_iterator;
    mhfs_cl_track_meta_tags_comment currentComment;
} mhfs_cl_track_meta_tags;

typedef struct {
    uint32_t pictureType;
    uint32_t mimeSize;
    const uint8_t *mime;
    uint32_t descSize;
    const uint8_t *desc;
    uint32_t pictureDataSize;
    const void *pictureData;
} mhfs_cl_track_meta_picture;

typedef void (*mhfs_cl_track_on_metablock)(void*, const mhfs_cl_track_meta, void *);

#define MHFS_CL_TRACK_MAX_ALLOCS 3
typedef struct {
    void *allocptrs[MHFS_CL_TRACK_MAX_ALLOCS];
    size_t allocsizes[MHFS_CL_TRACK_MAX_ALLOCS];
} mhfs_cl_track_allocs;

typedef struct {
    blockvf_error code;
    uint32_t extradata;
} mhfs_cl_track_blockvf_data;

typedef struct {
    // for backup and restore
    ma_decoder backupDecoder;
    unsigned backupFileOffset;
    mhfs_cl_track_allocs allocs;

    ma_decoder_config decoderConfig;
    ma_decoder decoder;
    bool dec_initialized;
    blockvf vf;
    mhfs_cl_track_blockvf_data vfData;
    mhfs_cl_track_meta_audioinfo meta;
    unsigned afterID3Offset;
    bool meta_initialized;
    uint32_t currentFrame;
} mhfs_cl_track;

typedef union {
    uint32_t frames_read;
    uint32_t needed_offset;
} mhfs_cl_track_return_data;

LIBEXPORT void mhfs_cl_track_init(mhfs_cl_track *pTrack, const unsigned blocksize);
LIBEXPORT void mhfs_cl_track_deinit(mhfs_cl_track *pTrack);
LIBEXPORT void *mhfs_cl_track_add_block(mhfs_cl_track *pTrack, const uint32_t block_start, const unsigned filesize);
LIBEXPORT mhfs_cl_error mhfs_cl_track_load_metadata(mhfs_cl_track *pTrack, mhfs_cl_track_return_data *pReturnData, const char *mime, const char *fullfilename, const uint64_t totalPCMFrameCount, const mhfs_cl_track_on_metablock on_metablock, void *con...
LIBEXPORT int mhfs_cl_track_seek_to_pcm_frame(mhfs_cl_track *pTrack, const uint32_t pcmFrameIndex);
LIBEXPORT mhfs_cl_error mhfs_cl_track_read_pcm_frames_f32(mhfs_cl_track *pTrack, const uint32_t desired_pcm_frames, float32_t *outFloat, mhfs_cl_track_return_data *pReturnData);

LIBEXPORT double mhfs_cl_track_meta_audioinfo_durationInSecs(const mhfs_cl_track_meta_audioinfo *pInfo);
LIBEXPORT const mhfs_cl_track_meta_tags_comment *mhfs_cl_track_meta_tags_next_comment(mhfs_cl_track_meta_tags *pTags);
#endif /* mhfs_cl_track.h */

#if defined(MHFSCLTRACK_IMPLEMENTATION)
#ifndef mhfs_cl_track_c
#define mhfs_cl_track_c

#ifndef MHFSCLTR_PRINT_ON
    #define MHFSCLTR_PRINT_ON 0
#endif

#define MHFSCLTR_PRINT(...) \
    do { if (MHFSCLTR_PRINT_ON) fprintf(stdout, __VA_ARGS__); } while (0)

#define mhfs_cl_member_size(type, member) sizeof(((type *)0)->member)

static inline uint32_t unaligned_beu32_to_native(const void *src)
{
    const uint8_t *pNum = src;
    return (pNum[0] << 24) | (pNum[1] << 16) | (pNum[2] << 8) | (pNum[3]);
}

static inline uint32_t unaligned_leu32_to_native(const void *src)
{
    const uint8_t *pNum = src;
    return (pNum[0]) | (pNum[1] << 8) | (pNum[2] << 16) | (pNum[3] << 24);
}

static inline uint32_t unaligned_leu16_to_native(const void *src)
{
    const uint8_t *pNum = src;
    return (pNum[0]) | (pNum[1] << 8);
}

share/public_html/static/music_worklet_inprogress/decoder/src/mhfs_cl_track.h  view on Meta::CPAN

    {
        if(pAllocs->allocptrs[i] == NULL)
        {
            const size_t rsz = ceil8(sz);
            uint8_t *res = malloc(rsz * 2);
            if(res == NULL)
            {
                MHFSCLTR_PRINT("%s: %zu malloc failed\n", __func__, sz);
            }
            MHFSCLTR_PRINT("%s: %zu %p\n", __func__, sz, res);
            pAllocs->allocsizes[i]= sz;
            pAllocs->allocptrs[i] = res;
            return res;
        }
    }
    MHFSCLTR_PRINT("%s: %zu failed to find slot for alloc\n", __func__, sz);
    return NULL;
}

static void mhfs_cl_track_free(void* p, void* pUserData)
{
    mhfs_cl_track *pTrack = (mhfs_cl_track *)pUserData;
    mhfs_cl_track_allocs *pAllocs = &pTrack->allocs;

    for(unsigned i = 0; i < MHFS_CL_TRACK_MAX_ALLOCS; i++)
    {
        if(pAllocs->allocptrs[i] == p)
        {
            MHFSCLTR_PRINT("%s: 0x%p\n", __func__, p);
            free(p);
            pAllocs->allocptrs[i] = NULL;
            return;
        }
    }
    MHFSCLTR_PRINT("%s: failed to record free %p\n", __func__, p);
}

static void *mhfs_cl_track_realloc(void *p, size_t sz, void* pUserData)
{
    if(p == NULL)
    {
        MHFSCLTR_PRINT("%s: %zu realloc passing to malloc\n", __func__, sz);
        return mhfs_cl_track_malloc(sz, pUserData);
    }
    else if(sz == 0)
    {
        MHFSCLTR_PRINT("%s: %zu realloc passing to free\n", __func__, sz);
        mhfs_cl_track_free(p, pUserData);
        return NULL;
    }

    mhfs_cl_track *pTrack = (mhfs_cl_track *)pUserData;
    mhfs_cl_track_allocs *pAllocs = &pTrack->allocs;
    for(unsigned i = 0; i < MHFS_CL_TRACK_MAX_ALLOCS; i++)
    {
        if(pAllocs->allocptrs[i] == p)
        {
            const size_t osz = pAllocs->allocsizes[i];
            const size_t orsz = ceil8(pAllocs->allocsizes[i]);
            const size_t rsz = ceil8(sz);
            // avoid losing the start of backup by moving it down
            if(rsz < orsz)
            {
                uint8_t *ogalloc = p;
                memmove(ogalloc+rsz, ogalloc+orsz, sz);
            }
            uint8_t *newalloc = realloc(p, rsz*2);
            if(newalloc == NULL)
            {
                if(rsz >= orsz)
                {
                    MHFSCLTR_PRINT("%s: %zu realloc failed\n", __func__, sz);
                    return NULL;
                }
                // we moved the data down so we can't fail
                newalloc = p;
            }
            // move the backup data forward
            else if(rsz > orsz)
            {
                memmove(newalloc+rsz, newalloc+orsz, osz);
            }

            pAllocs->allocsizes[i]= sz;
            pAllocs->allocptrs[i] = newalloc;
            return newalloc;
        }
    }
    MHFSCLTR_PRINT("%s: %zu failed to find\n", __func__, sz);
    return NULL;
}

static inline void mhfs_cl_track_allocs_backup_or_restore(mhfs_cl_track *pTrack, const bool backup)
{
    // copy ma_decoder and blockvf fileoffset
    if(backup)
    {
        pTrack->backupDecoder    = pTrack->decoder;
        pTrack->backupFileOffset = pTrack->vf.fileoffset;
    }
    else
    {
        pTrack->decoder       = pTrack->backupDecoder;
        pTrack->vf.fileoffset = pTrack->backupFileOffset;
    }

    // copy the allocations
    mhfs_cl_track_allocs *pAllocs = &pTrack->allocs;
    for(unsigned i = 0; i < MHFS_CL_TRACK_MAX_ALLOCS; i++)
    {
        if(pAllocs->allocptrs[i] != NULL)
        {
            const size_t offset = ceil8(pAllocs->allocsizes[i]);
            uint8_t *allocBuf = pAllocs->allocptrs[i];
            const uint8_t *srcBuf;
            uint8_t *destBuf;
            if(backup)
            {
                srcBuf = allocBuf;
                destBuf = allocBuf + offset;
            }
            else
            {
                srcBuf = allocBuf + offset;
                destBuf = allocBuf;
            }
            memcpy(destBuf, srcBuf, pAllocs->allocsizes[i]);
        }
    }
}

static inline void mhfs_cl_track_allocs_backup(mhfs_cl_track *pTrack)
{
    return mhfs_cl_track_allocs_backup_or_restore(pTrack, true);
}

static inline void mhfs_cl_track_allocs_restore(mhfs_cl_track *pTrack)
{
    return mhfs_cl_track_allocs_backup_or_restore(pTrack, false);
}

void mhfs_cl_track_init(mhfs_cl_track *pTrack, const unsigned blocksize)
{
    for(unsigned i = 0; i < MHFS_CL_TRACK_MAX_ALLOCS; i++)
    {
        pTrack->allocs.allocptrs[i] = NULL;
    }
    pTrack->decoderConfig = ma_decoder_config_init(ma_format_f32, 0, 0);
    ma_allocation_callbacks cbs;
    cbs.pUserData = pTrack;
    cbs.onMalloc = &mhfs_cl_track_malloc;
    cbs.onRealloc = &mhfs_cl_track_realloc;
    cbs.onFree = &mhfs_cl_track_free;
    pTrack->decoderConfig.allocationCallbacks = cbs;
    pTrack->decoderConfig.encodingFormat = ma_encoding_format_unknown;

    pTrack->dec_initialized = false;
    blockvf_init(&pTrack->vf, blocksize);
    pTrack->meta_initialized = false;
    pTrack->currentFrame = 0;
}

void mhfs_cl_track_deinit(mhfs_cl_track *pTrack)
{
    if(pTrack->dec_initialized) ma_decoder_uninit(&pTrack->decoder);
    blockvf_deinit(&pTrack->vf);
}

void *mhfs_cl_track_add_block(mhfs_cl_track *pTrack, const uint32_t block_start, const unsigned filesize)
{
    return blockvf_add_block(&pTrack->vf, block_start, filesize);
}

// mhfs_cl_track_read_pcm_frames_f32 will catch the error if we dont here
int mhfs_cl_track_seek_to_pcm_frame(mhfs_cl_track *pTrack, const uint32_t pcmFrameIndex)
{
    if(pTrack->dec_initialized)
    {
        if(pcmFrameIndex >= pTrack->meta.totalPCMFrameCount)
        {
            // allow seeking to 0 always
            if(pcmFrameIndex != 0)
            {
                return 0;
            }
        }
    }
    pTrack->currentFrame = pcmFrameIndex;
    return 1;
}

double mhfs_cl_track_meta_audioinfo_durationInSecs(const mhfs_cl_track_meta_audioinfo *pInfo)
{
    return (pInfo->sampleRate > 0) ? ((double)pInfo->totalPCMFrameCount / pInfo->sampleRate) : 0;
}

typedef enum {
	DAF_FLAC,
	DAF_MP3,

share/public_html/static/music_worklet_inprogress/decoder/src/mhfs_cl_track.h  view on Meta::CPAN

            if(chunkSize > 16)
            {

            }

            /*
            The bytes per frame is a bit ambiguous. It can be either be based on the bits per sample, or the block align. The way I'm doing it here
            is that if the bits per sample is a multiple of 8, use floor(bitsPerSample*channels/8), otherwise fall back to the block align.
            */
            if ((bitsPerSample & 0x7) == 0) {
                /* Bits per sample is a multiple of 8. */
                bytesPerPCMFrame = (bitsPerSample * channels) >> 3;
            } else {
                bytesPerPCMFrame = blockAlign;
            }

            /* Validation for known formats. a-law and mu-law should be 1 byte per channel. If it's not, it's not decodable. */
            if (audioFormat == DR_WAVE_FORMAT_ALAW || audioFormat == DR_WAVE_FORMAT_MULAW) {
                if (bytesPerPCMFrame != channels) {
                    return MHFS_CL_ERROR;
                }
            }
            bGotFmt = true;
        }
        else if(chunkType == MCT_WAVE_CHUNK_DATA)
        {
            if(!bGotFmt)
            {
                return MHFS_CL_ERROR;
            }
            totalPCMFrameCount = chunkSize / bytesPerPCMFrame;
            mhfs_cl_track_meta_audioinfo_init(&pTrack->meta, totalPCMFrameCount, sampleRate, channels, MCT_MAI_FLD_BITSPERSAMPLE, bitsPerSample, 0);
            if(on_metablock != NULL)
            {
                on_metablock(context, MHFS_CL_TRACK_M_AUDIOINFO, &pTrack->meta);
            }
            pTrack->meta_initialized = true;
            MHFSCLTR_PRINT("self initialized metadata from wav\n");
            return MHFS_CL_SUCCESS;
        }
        else
        {
            const blockvf_error chunkSkipError = blockvf_seek(&pTrack->vf, chunkSize, blockvf_seek_origin_current);
            if(chunkSkipError != BLOCKVF_SUCCESS)
            {
                return mhfs_cl_error_from_blockvf_error(chunkSkipError);
            }
        }
    } while(1);

    return MHFS_CL_ERROR;
}



static inline void mhfs_cl_track_blockvf_ma_decoder_call_before(mhfs_cl_track *pTrack, const bool bSaveDecoder)
{
    pTrack->vfData.code = BLOCKVF_SUCCESS;
    if(bSaveDecoder)
    {
        mhfs_cl_track_allocs_backup(pTrack);
    }
}

static inline mhfs_cl_error mhfs_cl_track_blockvf_ma_decoder_call_after(mhfs_cl_track *pTrack, const bool bRestoreDecoder, uint32_t *pNeededOffset)
{
    if(pTrack->vfData.code != BLOCKVF_SUCCESS)
    {
        *pNeededOffset = pTrack->vfData.extradata;
        if(bRestoreDecoder)
        {
            mhfs_cl_track_allocs_restore(pTrack);
        }
    }
    return mhfs_cl_error_from_blockvf_error(pTrack->vfData.code);
}

static mhfs_cl_error mhfs_cl_track_open_ma_decoder(mhfs_cl_track *pTrack, uint32_t *pNeededOffset)
{
    pTrack->vf.fileoffset = 0;
    mhfs_cl_track_blockvf_ma_decoder_call_before(pTrack, false);
    const ma_result openRes = ma_decoder_init(&mhfs_cl_track_on_read_ma_decoder, &mhfs_cl_track_on_seek_ma_decoder, pTrack, &pTrack->decoderConfig, &pTrack->decoder);
    const mhfs_cl_error openBlockRes = mhfs_cl_track_blockvf_ma_decoder_call_after(pTrack, false, pNeededOffset);
    if(openBlockRes != MHFS_CL_SUCCESS)
    {
        if(openRes == MA_SUCCESS) ma_decoder_uninit(&pTrack->decoder);
        return openBlockRes;
    }
    else if(openRes == MA_SUCCESS)
    {
        pTrack->dec_initialized = true;
        return MHFS_CL_SUCCESS;
    }
    return MHFS_CL_ERROR;
}

static mhfs_cl_error mhfs_cl_track_load_metadata_ma_decoder(mhfs_cl_track *pTrack, mhfs_cl_track_return_data *pReturnData, const mhfs_cl_track_on_metablock on_metablock, void *context)
{
    // open the decoder
    mhfs_cl_error retval = mhfs_cl_track_open_ma_decoder(pTrack, &pReturnData->needed_offset);
    if(retval != MHFS_CL_SUCCESS)
    {
        return retval;
    }

    // read and store the metadata
    const unsigned savefileoffset = pTrack->vf.fileoffset;
    uint64_t totalPCMFrameCount = pTrack->meta.totalPCMFrameCount;
    if(pTrack->decoderConfig.encodingFormat != ma_encoding_format_mp3)
    {
        ma_decoder_get_length_in_pcm_frames(&pTrack->decoder, &totalPCMFrameCount);
    }
    MHFSCLTR_PRINT("decoder output samplerate %u\n", pTrack->decoder.outputSampleRate);
    mhfs_cl_track_meta_audioinfo_init(&pTrack->meta, totalPCMFrameCount, pTrack->decoder.outputSampleRate, pTrack->decoder.outputChannels, MCT_MAI_FLD_EMPTY, 0, 0);
    if(on_metablock != NULL)
    {
        on_metablock(context, MHFS_CL_TRACK_M_AUDIOINFO, &pTrack->meta);
    }

    if(retval == MHFS_CL_SUCCESS)
    {



( run in 1.630 second using v1.01-cache-2.11-cpan-df04353d9ac )