view release on metacpan or search on metacpan
share/public_html/static/music_inc/src/dr_flac.h view on Meta::CPAN
/*
FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
dr_flac - v0.12.20 - 2020-09-08
David Reid - mackron@gmail.com
GitHub: https://github.com/mackron/dr_libs
*/
/*
RELEASE NOTES - v0.12.0
=======================
Version 0.12.0 has breaking API changes including changes to the existing API and the removal of deprecated APIs.
Improved Client-Defined Memory Allocation
-----------------------------------------
The main change with this release is the addition of a more flexible way of implementing custom memory allocation routines. The
existing system of DRFLAC_MALLOC, DRFLAC_REALLOC and DRFLAC_FREE are still in place and will be used by default when no custom
allocation callbacks are specified.
To use the new system, you pass in a pointer to a drflac_allocation_callbacks object to drflac_open() and family, like this:
void* my_malloc(size_t sz, void* pUserData)
{
return malloc(sz);
}
void* my_realloc(void* p, size_t sz, void* pUserData)
{
return realloc(p, sz);
}
void my_free(void* p, void* pUserData)
{
free(p);
}
...
drflac_allocation_callbacks allocationCallbacks;
allocationCallbacks.pUserData = &myData;
allocationCallbacks.onMalloc = my_malloc;
allocationCallbacks.onRealloc = my_realloc;
allocationCallbacks.onFree = my_free;
drflac* pFlac = drflac_open_file("my_file.flac", &allocationCallbacks);
The advantage of this new system is that it allows you to specify user data which will be passed in to the allocation routines.
Passing in null for the allocation callbacks object will cause dr_flac to use defaults which is the same as DRFLAC_MALLOC,
DRFLAC_REALLOC and DRFLAC_FREE and the equivalent of how it worked in previous versions.
Every API that opens a drflac object now takes this extra parameter. These include the following:
drflac_open()
drflac_open_relaxed()
drflac_open_with_metadata()
drflac_open_with_metadata_relaxed()
drflac_open_file()
drflac_open_file_with_metadata()
drflac_open_memory()
drflac_open_memory_with_metadata()
drflac_open_and_read_pcm_frames_s32()
drflac_open_and_read_pcm_frames_s16()
drflac_open_and_read_pcm_frames_f32()
drflac_open_file_and_read_pcm_frames_s32()
drflac_open_file_and_read_pcm_frames_s16()
drflac_open_file_and_read_pcm_frames_f32()
drflac_open_memory_and_read_pcm_frames_s32()
drflac_open_memory_and_read_pcm_frames_s16()
drflac_open_memory_and_read_pcm_frames_f32()
Optimizations
-------------
Seeking performance has been greatly improved. A new binary search based seeking algorithm has been introduced which significantly
improves performance over the brute force method which was used when no seek table was present. Seek table based seeking also takes
advantage of the new binary search seeking system to further improve performance there as well. Note that this depends on CRC which
means it will be disabled when DR_FLAC_NO_CRC is used.
The SSE4.1 pipeline has been cleaned up and optimized. You should see some improvements with decoding speed of 24-bit files in
particular. 16-bit streams should also see some improvement.
drflac_read_pcm_frames_s16() has been optimized. Previously this sat on top of drflac_read_pcm_frames_s32() and performed it's s32
to s16 conversion in a second pass. This is now all done in a single pass. This includes SSE2 and ARM NEON optimized paths.
A minor optimization has been implemented for drflac_read_pcm_frames_s32(). This will now use an SSE2 optimized pipeline for stereo
channel reconstruction which is the last part of the decoding process.
The ARM build has seen a few improvements. The CLZ (count leading zeroes) and REV (byte swap) instructions are now used when
compiling with GCC and Clang which is achieved using inline assembly. The CLZ instruction requires ARM architecture version 5 at
compile time and the REV instruction requires ARM architecture version 6.
An ARM NEON optimized pipeline has been implemented. To enable this you'll need to add -mfpu=neon to the command line when compiling.
Removed APIs
------------
The following APIs were deprecated in version 0.11.0 and have been completely removed in version 0.12.0:
drflac_read_s32() -> drflac_read_pcm_frames_s32()
drflac_read_s16() -> drflac_read_pcm_frames_s16()
drflac_read_f32() -> drflac_read_pcm_frames_f32()
drflac_seek_to_sample() -> drflac_seek_to_pcm_frame()
drflac_open_and_decode_s32() -> drflac_open_and_read_pcm_frames_s32()
drflac_open_and_decode_s16() -> drflac_open_and_read_pcm_frames_s16()
drflac_open_and_decode_f32() -> drflac_open_and_read_pcm_frames_f32()
drflac_open_and_decode_file_s32() -> drflac_open_file_and_read_pcm_frames_s32()
drflac_open_and_decode_file_s16() -> drflac_open_file_and_read_pcm_frames_s16()
drflac_open_and_decode_file_f32() -> drflac_open_file_and_read_pcm_frames_f32()
drflac_open_and_decode_memory_s32() -> drflac_open_memory_and_read_pcm_frames_s32()
drflac_open_and_decode_memory_s16() -> drflac_open_memory_and_read_pcm_frames_s16()
drflac_open_and_decode_memory_f32() -> drflac_open_memroy_and_read_pcm_frames_f32()
Prior versions of dr_flac operated on a per-sample basis whereas now it operates on PCM frames. The removed APIs all relate
to the old per-sample APIs. You now need to use the "pcm_frame" versions.
*/
/*
Introduction
============
dr_flac is a single file library. To use it, do something like the following in one .c file.
```c
#define DR_FLAC_IMPLEMENTATION
#include "dr_flac.h"
```
You can then #include this file in other parts of the program as you would with any other header file. To decode audio data, do something like the following:
```c
drflac* pFlac = drflac_open_file("MySong.flac", NULL);
if (pFlac == NULL) {
// Failed to open FLAC file
}
drflac_int32* pSamples = malloc(pFlac->totalPCMFrameCount * pFlac->channels * sizeof(drflac_int32));
drflac_uint64 numberOfInterleavedSamplesActuallyRead = drflac_read_pcm_frames_s32(pFlac, pFlac->totalPCMFrameCount, pSamples);
```
The drflac object represents the decoder. It is a transparent type so all the information you need, such as the number of channels and the bits per sample,
should be directly accessible - just make sure you don't change their values. Samples are always output as interleaved signed 32-bit PCM. In the example above
a native FLAC stream was opened, however dr_flac has seamless support for Ogg encapsulated FLAC streams as well.
You do not need to decode the entire stream in one go - you just specify how many samples you'd like at any given time and the decoder will give you as many
samples as it can, up to the amount requested. Later on when you need the next batch of samples, just call it again. Example:
```c
while (drflac_read_pcm_frames_s32(pFlac, chunkSizeInPCMFrames, pChunkSamples) > 0) {
do_something();
}
```
You can seek to a specific PCM frame with `drflac_seek_to_pcm_frame()`.
If you just want to quickly decode an entire FLAC file in one go you can do something like this:
```c
unsigned int channels;
unsigned int sampleRate;
drflac_uint64 totalPCMFrameCount;
drflac_int32* pSampleData = drflac_open_file_and_read_pcm_frames_s32("MySong.flac", &channels, &sampleRate, &totalPCMFrameCount, NULL);
if (pSampleData == NULL) {
// Failed to open and decode FLAC file.
}
...
drflac_free(pSampleData);
```
You can read samples as signed 16-bit integer and 32-bit floating-point PCM with the *_s16() and *_f32() family of APIs respectively, but note that these
should be considered lossy.
If you need access to metadata (album art, etc.), use `drflac_open_with_metadata()`, `drflac_open_file_with_metdata()` or `drflac_open_memory_with_metadata()`.
The rationale for keeping these APIs separate is that they're slightly slower than the normal versions and also just a little bit harder to use. dr_flac
reports metadata to the application through the use of a callback, and every metadata block is reported before `drflac_open_with_metdata()` returns.
The main opening APIs (`drflac_open()`, etc.) will fail if the header is not present. The presents a problem in certain scenarios such as broadcast style
streams or internet radio where the header may not be present because the user has started playback mid-stream. To handle this, use the relaxed APIs:
`drflac_open_relaxed()`
`drflac_open_with_metadata_relaxed()`
It is not recommended to use these APIs for file based streams because a missing header would usually indicate a corrupt or perverse file. In addition, these
APIs can take a long time to initialize because they may need to spend a lot of time finding the first frame.
Build Options
=============
#define these options before including this file.
#define DR_FLAC_NO_STDIO
Disable `drflac_open_file()` and family.
#define DR_FLAC_NO_OGG
Disables support for Ogg/FLAC streams.
#define DR_FLAC_BUFFER_SIZE <number>
Defines the size of the internal buffer to store data from onRead(). This buffer is used to reduce the number of calls back to the client for more data.
Larger values means more memory, but better performance. My tests show diminishing returns after about 4KB (which is the default). Consider reducing this if
you have a very efficient implementation of onRead(), or increase it if it's very inefficient. Must be a multiple of 8.
#define DR_FLAC_NO_CRC
Disables CRC checks. This will offer a performance boost when CRC is unnecessary. This will disable binary search seeking. When seeking, the seek table will
be used if available. Otherwise the seek will be performed using brute force.
#define DR_FLAC_NO_SIMD
Disables SIMD optimizations (SSE on x86/x64 architectures, NEON on ARM architectures). Use this if you are having compatibility issues with your compiler.
Notes
=====
- dr_flac does not support changing the sample rate nor channel count mid stream.
- dr_flac is not thread-safe, but its APIs can be called from any thread so long as you do your own synchronization.
- When using Ogg encapsulation, a corrupted metadata block will result in `drflac_open_with_metadata()` and `drflac_open()` returning inconsistent samples due
to differences in corrupted stream recorvery logic between the two APIs.
*/
#ifndef dr_flac_h
#define dr_flac_h
#ifdef __cplusplus
extern "C" {
#endif
#define DRFLAC_STRINGIFY(x) #x
#define DRFLAC_XSTRINGIFY(x) DRFLAC_STRINGIFY(x)
#define DRFLAC_VERSION_MAJOR 0
#define DRFLAC_VERSION_MINOR 12
#define DRFLAC_VERSION_REVISION 20
#define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION)
#include <stddef.h> /* For size_t. */
/* Sized types. */
typedef signed char drflac_int8;
typedef unsigned char drflac_uint8;
typedef signed short drflac_int16;
typedef unsigned short drflac_uint16;
typedef signed int drflac_int32;
typedef unsigned int drflac_uint32;
#if defined(_MSC_VER)
share/public_html/static/music_inc/src/dr_flac.h view on Meta::CPAN
#define DRFLAC_64BIT
#endif
#ifdef DRFLAC_64BIT
typedef drflac_uint64 drflac_cache_t;
#else
typedef drflac_uint32 drflac_cache_t;
#endif
/* The various metadata block types. */
#define DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO 0
#define DRFLAC_METADATA_BLOCK_TYPE_PADDING 1
#define DRFLAC_METADATA_BLOCK_TYPE_APPLICATION 2
#define DRFLAC_METADATA_BLOCK_TYPE_SEEKTABLE 3
#define DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT 4
#define DRFLAC_METADATA_BLOCK_TYPE_CUESHEET 5
#define DRFLAC_METADATA_BLOCK_TYPE_PICTURE 6
#define DRFLAC_METADATA_BLOCK_TYPE_INVALID 127
/* The various picture types specified in the PICTURE block. */
#define DRFLAC_PICTURE_TYPE_OTHER 0
#define DRFLAC_PICTURE_TYPE_FILE_ICON 1
#define DRFLAC_PICTURE_TYPE_OTHER_FILE_ICON 2
#define DRFLAC_PICTURE_TYPE_COVER_FRONT 3
#define DRFLAC_PICTURE_TYPE_COVER_BACK 4
#define DRFLAC_PICTURE_TYPE_LEAFLET_PAGE 5
#define DRFLAC_PICTURE_TYPE_MEDIA 6
#define DRFLAC_PICTURE_TYPE_LEAD_ARTIST 7
#define DRFLAC_PICTURE_TYPE_ARTIST 8
#define DRFLAC_PICTURE_TYPE_CONDUCTOR 9
#define DRFLAC_PICTURE_TYPE_BAND 10
#define DRFLAC_PICTURE_TYPE_COMPOSER 11
#define DRFLAC_PICTURE_TYPE_LYRICIST 12
#define DRFLAC_PICTURE_TYPE_RECORDING_LOCATION 13
#define DRFLAC_PICTURE_TYPE_DURING_RECORDING 14
#define DRFLAC_PICTURE_TYPE_DURING_PERFORMANCE 15
#define DRFLAC_PICTURE_TYPE_SCREEN_CAPTURE 16
#define DRFLAC_PICTURE_TYPE_BRIGHT_COLORED_FISH 17
#define DRFLAC_PICTURE_TYPE_ILLUSTRATION 18
#define DRFLAC_PICTURE_TYPE_BAND_LOGOTYPE 19
#define DRFLAC_PICTURE_TYPE_PUBLISHER_LOGOTYPE 20
typedef enum
{
drflac_container_native,
drflac_container_ogg,
drflac_container_unknown
} drflac_container;
typedef enum
{
drflac_seek_origin_start,
drflac_seek_origin_current
} drflac_seek_origin;
/* Packing is important on this structure because we map this directly to the raw data within the SEEKTABLE metadata block. */
#pragma pack(2)
typedef struct
{
drflac_uint64 firstPCMFrame;
drflac_uint64 flacFrameOffset; /* The offset from the first byte of the header of the first frame. */
drflac_uint16 pcmFrameCount;
} drflac_seekpoint;
#pragma pack()
typedef struct
{
drflac_uint16 minBlockSizeInPCMFrames;
drflac_uint16 maxBlockSizeInPCMFrames;
drflac_uint32 minFrameSizeInPCMFrames;
drflac_uint32 maxFrameSizeInPCMFrames;
drflac_uint32 sampleRate;
drflac_uint8 channels;
drflac_uint8 bitsPerSample;
drflac_uint64 totalPCMFrameCount;
drflac_uint8 md5[16];
} drflac_streaminfo;
typedef struct
{
/* The metadata type. Use this to know how to interpret the data below. */
drflac_uint32 type;
/*
A pointer to the raw data. This points to a temporary buffer so don't hold on to it. It's best to
not modify the contents of this buffer. Use the structures below for more meaningful and structured
information about the metadata. It's possible for this to be null.
*/
const void* pRawData;
/* The size in bytes of the block and the buffer pointed to by pRawData if it's non-NULL. */
drflac_uint32 rawDataSize;
union
{
drflac_streaminfo streaminfo;
struct
{
int unused;
} padding;
struct
{
drflac_uint32 id;
const void* pData;
drflac_uint32 dataSize;
} application;
struct
{
drflac_uint32 seekpointCount;
const drflac_seekpoint* pSeekpoints;
} seektable;
struct
{
drflac_uint32 vendorLength;
const char* vendor;
drflac_uint32 commentCount;
const void* pComments;
share/public_html/static/music_inc/src/dr_flac.h view on Meta::CPAN
const drflac_uint8* pPictureData;
} picture;
} data;
} drflac_metadata;
/*
Callback for when data needs to be read from the client.
Parameters
----------
pUserData (in)
The user data that was passed to drflac_open() and family.
pBufferOut (out)
The output buffer.
bytesToRead (in)
The number of bytes to read.
Return Value
------------
The number of bytes actually read.
Remarks
-------
A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback until either the entire bytesToRead is filled or
you have reached the end of the stream.
*/
typedef size_t (* drflac_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead);
/*
Callback for when data needs to be seeked.
Parameters
----------
pUserData (in)
The user data that was passed to drflac_open() and family.
offset (in)
The number of bytes to move, relative to the origin. Will never be negative.
origin (in)
The origin of the seek - the current position or the start of the stream.
Return Value
------------
Whether or not the seek was successful.
Remarks
-------
The offset will never be negative. Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which will be
either drflac_seek_origin_start or drflac_seek_origin_current.
When seeking to a PCM frame using drflac_seek_to_pcm_frame(), dr_flac may call this with an offset beyond the end of the FLAC stream. This needs to be detected
and handled by returning DRFLAC_FALSE.
*/
typedef drflac_bool32 (* drflac_seek_proc)(void* pUserData, int offset, drflac_seek_origin origin);
/*
Callback for when a metadata block is read.
Parameters
----------
pUserData (in)
The user data that was passed to drflac_open() and family.
pMetadata (in)
A pointer to a structure containing the data of the metadata block.
Remarks
-------
Use pMetadata->type to determine which metadata block is being handled and how to read the data.
*/
typedef void (* drflac_meta_proc)(void* pUserData, drflac_metadata* pMetadata);
typedef struct
{
void* pUserData;
void* (* onMalloc)(size_t sz, void* pUserData);
void* (* onRealloc)(void* p, size_t sz, void* pUserData);
void (* onFree)(void* p, void* pUserData);
} drflac_allocation_callbacks;
/* Structure for internal use. Only used for decoders opened with drflac_open_memory. */
typedef struct
{
const drflac_uint8* data;
size_t dataSize;
size_t currentReadPos;
} drflac__memory_stream;
/* Structure for internal use. Used for bit streaming. */
typedef struct
{
/* The function to call when more data needs to be read. */
drflac_read_proc onRead;
/* The function to call when the current read position needs to be moved. */
drflac_seek_proc onSeek;
/* The user data to pass around to onRead and onSeek. */
void* pUserData;
/*
The number of unaligned bytes in the L2 cache. This will always be 0 until the end of the stream is hit. At the end of the
stream there will be a number of bytes that don't cleanly fit in an L1 cache line, so we use this variable to know whether
or not the bistreamer needs to run on a slower path to read those last bytes. This will never be more than sizeof(drflac_cache_t).
*/
size_t unalignedByteCount;
/* The content of the unaligned bytes. */
drflac_cache_t unalignedCache;
/* The index of the next valid cache line in the "L2" cache. */
drflac_uint32 nextL2Line;
/* The number of bits that have been consumed by the cache. This is used to determine how many valid bits are remaining. */
drflac_uint32 consumedBits;
/*
The cached data which was most recently read from the client. There are two levels of cache. Data flows as such:
Client -> L2 -> L1. The L2 -> L1 movement is aligned and runs on a fast path in just a few instructions.
*/
drflac_cache_t cacheL2[DR_FLAC_BUFFER_SIZE/sizeof(drflac_cache_t)];
drflac_cache_t cache;
/*
CRC-16. This is updated whenever bits are read from the bit stream. Manually set this to 0 to reset the CRC. For FLAC, this
is reset to 0 at the beginning of each frame.
*/
drflac_uint16 crc16;
drflac_cache_t crc16Cache; /* A cache for optimizing CRC calculations. This is filled when when the L1 cache is reloaded. */
drflac_uint32 crc16CacheIgnoredBytes; /* The number of bytes to ignore when updating the CRC-16 from the CRC-16 cache. */
} drflac_bs;
typedef struct
{
/* The type of the subframe: SUBFRAME_CONSTANT, SUBFRAME_VERBATIM, SUBFRAME_FIXED or SUBFRAME_LPC. */
drflac_uint8 subframeType;
/* The number of wasted bits per sample as specified by the sub-frame header. */
drflac_uint8 wastedBitsPerSample;
/* The order to use for the prediction stage for SUBFRAME_FIXED and SUBFRAME_LPC. */
drflac_uint8 lpcOrder;
/* A pointer to the buffer containing the decoded samples in the subframe. This pointer is an offset from drflac::pExtraData. */
drflac_int32* pSamplesS32;
} drflac_subframe;
typedef struct
{
/*
If the stream uses variable block sizes, this will be set to the index of the first PCM frame. If fixed block sizes are used, this will
always be set to 0. This is 64-bit because the decoded PCM frame number will be 36 bits.
*/
drflac_uint64 pcmFrameNumber;
/*
If the stream uses fixed block sizes, this will be set to the frame number. If variable block sizes are used, this will always be 0. This
is 32-bit because in fixed block sizes, the maximum frame number will be 31 bits.
*/
drflac_uint32 flacFrameNumber;
/* The sample rate of this frame. */
drflac_uint32 sampleRate;
/* The number of PCM frames in each sub-frame within this frame. */
drflac_uint16 blockSizeInPCMFrames;
/*
The channel assignment of this frame. This is not always set to the channel count. If interchannel decorrelation is being used this
will be set to DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE, DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE or DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE.
*/
drflac_uint8 channelAssignment;
/* The number of bits per sample within this frame. */
drflac_uint8 bitsPerSample;
/* The frame's CRC. */
drflac_uint8 crc8;
} drflac_frame_header;
typedef struct
{
/* The header. */
drflac_frame_header header;
/*
The number of PCM frames left to be read in this FLAC frame. This is initially set to the block size. As PCM frames are read,
this will be decremented. When it reaches 0, the decoder will see this frame as fully consumed and load the next frame.
*/
drflac_uint32 pcmFramesRemaining;
/* The list of sub-frames within the frame. There is one sub-frame for each channel, and there's a maximum of 8 channels. */
drflac_subframe subframes[8];
} drflac_frame;
typedef struct
{
/* The function to call when a metadata block is read. */
drflac_meta_proc onMeta;
/* The user data posted to the metadata callback function. */
void* pUserDataMD;
/* Memory allocation callbacks. */
drflac_allocation_callbacks allocationCallbacks;
/* The sample rate. Will be set to something like 44100. */
drflac_uint32 sampleRate;
/*
The number of channels. This will be set to 1 for monaural streams, 2 for stereo, etc. Maximum 8. This is set based on the
value specified in the STREAMINFO block.
*/
drflac_uint8 channels;
/* The bits per sample. Will be set to something like 16, 24, etc. */
drflac_uint8 bitsPerSample;
/* The maximum block size, in samples. This number represents the number of samples in each channel (not combined). */
drflac_uint16 maxBlockSizeInPCMFrames;
/*
The total number of PCM Frames making up the stream. Can be 0 in which case it's still a valid stream, but just means
the total PCM frame count is unknown. Likely the case with streams like internet radio.
*/
drflac_uint64 totalPCMFrameCount;
/* The container type. This is set based on whether or not the decoder was opened from a native or Ogg stream. */
drflac_container container;
/* The number of seekpoints in the seektable. */
drflac_uint32 seekpointCount;
/* Information about the frame the decoder is currently sitting on. */
drflac_frame currentFLACFrame;
/* The index of the PCM frame the decoder is currently sitting on. This is only used for seeking. */
drflac_uint64 currentPCMFrame;
/* The position of the first FLAC frame in the stream. This is only ever used for seeking. */
drflac_uint64 firstFLACFramePosInBytes;
/* A hack to avoid a malloc() when opening a decoder with drflac_open_memory(). */
drflac__memory_stream memoryStream;
/* A pointer to the decoded sample data. This is an offset of pExtraData. */
drflac_int32* pDecodedSamples;
/* A pointer to the seek table. This is an offset of pExtraData, or NULL if there is no seek table. */
drflac_seekpoint* pSeekpoints;
/* Internal use only. Only used with Ogg containers. Points to a drflac_oggbs object. This is an offset of pExtraData. */
void* _oggbs;
/* Internal use only. Used for profiling and testing different seeking modes. */
drflac_bool32 _noSeekTableSeek : 1;
drflac_bool32 _noBinarySearchSeek : 1;
drflac_bool32 _noBruteForceSeek : 1;
/* The bit streamer. The raw FLAC data is fed through this object. */
drflac_bs bs;
/* Variable length extra data. We attach this to the end of the object so we can avoid unnecessary mallocs. */
drflac_uint8 pExtraData[1];
} drflac;
/*
Opens a FLAC decoder.
Parameters
----------
onRead (in)
The function to call when data needs to be read from the client.
onSeek (in)
The function to call when the read position of the client data needs to move.
pUserData (in, optional)
A pointer to application defined data that will be passed to onRead and onSeek.
pAllocationCallbacks (in, optional)
A pointer to application defined callbacks for managing memory allocations.
Return Value
------------
Returns a pointer to an object representing the decoder.
Remarks
-------
Close the decoder with `drflac_close()`.
`pAllocationCallbacks` can be NULL in which case it will use `DRFLAC_MALLOC`, `DRFLAC_REALLOC` and `DRFLAC_FREE`.
This function will automatically detect whether or not you are attempting to open a native or Ogg encapsulated FLAC, both of which should work seamlessly
without any manual intervention. Ogg encapsulation also works with multiplexed streams which basically means it can play FLAC encoded audio tracks in videos.
This is the lowest level function for opening a FLAC stream. You can also use `drflac_open_file()` and `drflac_open_memory()` to open the stream from a file or
from a block of memory respectively.
The STREAMINFO block must be present for this to succeed. Use `drflac_open_relaxed()` to open a FLAC stream where the header may not be present.
Seek Also
---------
drflac_open_file()
drflac_open_memory()
drflac_open_with_metadata()
drflac_close()
*/
DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
/*
Opens a FLAC stream with relaxed validation of the header block.
Parameters
----------
onRead (in)
The function to call when data needs to be read from the client.
onSeek (in)
The function to call when the read position of the client data needs to move.
container (in)
Whether or not the FLAC stream is encapsulated using standard FLAC encapsulation or Ogg encapsulation.
pUserData (in, optional)
A pointer to application defined data that will be passed to onRead and onSeek.
pAllocationCallbacks (in, optional)
A pointer to application defined callbacks for managing memory allocations.
Return Value
------------
A pointer to an object representing the decoder.
Remarks
-------
The same as drflac_open(), except attempts to open the stream even when a header block is not present.
Because the header is not necessarily available, the caller must explicitly define the container (Native or Ogg). Do not set this to `drflac_container_unknown`
as that is for internal use only.
Opening in relaxed mode will continue reading data from onRead until it finds a valid frame. If a frame is never found it will continue forever. To abort,
force your `onRead` callback to return 0, which dr_flac will use as an indicator that the end of the stream was found.
*/
DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
/*
Opens a FLAC decoder and notifies the caller of the metadata chunks (album art, etc.).
Parameters
----------
onRead (in)
The function to call when data needs to be read from the client.
onSeek (in)
The function to call when the read position of the client data needs to move.
onMeta (in)
The function to call for every metadata block.
pUserData (in, optional)
A pointer to application defined data that will be passed to onRead, onSeek and onMeta.
pAllocationCallbacks (in, optional)
A pointer to application defined callbacks for managing memory allocations.
Return Value
------------
A pointer to an object representing the decoder.
Remarks
-------
Close the decoder with `drflac_close()`.
`pAllocationCallbacks` can be NULL in which case it will use `DRFLAC_MALLOC`, `DRFLAC_REALLOC` and `DRFLAC_FREE`.
This is slower than `drflac_open()`, so avoid this one if you don't need metadata. Internally, this will allocate and free memory on the heap for every
metadata block except for STREAMINFO and PADDING blocks.
The caller is notified of the metadata via the `onMeta` callback. All metadata blocks will be handled before the function returns.
The STREAMINFO block must be present for this to succeed. Use `drflac_open_with_metadata_relaxed()` to open a FLAC stream where the header may not be present.
Note that this will behave inconsistently with `drflac_open()` if the stream is an Ogg encapsulated stream and a metadata block is corrupted. This is due to
the way the Ogg stream recovers from corrupted pages. When `drflac_open_with_metadata()` is being used, the open routine will try to read the contents of the
metadata block, whereas `drflac_open()` will simply seek past it (for the sake of efficiency). This inconsistency can result in different samples being
returned depending on whether or not the stream is being opened with metadata.
Seek Also
---------
drflac_open_file_with_metadata()
drflac_open_memory_with_metadata()
drflac_open()
drflac_close()
*/
DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
/*
The same as drflac_open_with_metadata(), except attempts to open the stream even when a header block is not present.
See Also
--------
drflac_open_with_metadata()
drflac_open_relaxed()
*/
DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
/*
Closes the given FLAC decoder.
Parameters
----------
pFlac (in)
The decoder to close.
Remarks
-------
This will destroy the decoder object.
See Also
--------
drflac_open()
drflac_open_with_metadata()
drflac_open_file()
drflac_open_file_w()
drflac_open_file_with_metadata()
drflac_open_file_with_metadata_w()
drflac_open_memory()
drflac_open_memory_with_metadata()
*/
DRFLAC_API void drflac_close(drflac* pFlac);
/*
Reads sample data from the given FLAC decoder, output as interleaved signed 32-bit PCM.
Parameters
----------
pFlac (in)
The decoder.
framesToRead (in)
The number of PCM frames to read.
pBufferOut (out, optional)
A pointer to the buffer that will receive the decoded samples.
Return Value
------------
Returns the number of PCM frames actually read. If the return value is less than `framesToRead` it has reached the end.
Remarks
-------
pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of frames seeked.
*/
DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s32(drflac* pFlac, drflac_uint64 framesToRead, drflac_int32* pBufferOut);
/*
Reads sample data from the given FLAC decoder, output as interleaved signed 16-bit PCM.
Parameters
----------
pFlac (in)
The decoder.
framesToRead (in)
The number of PCM frames to read.
pBufferOut (out, optional)
A pointer to the buffer that will receive the decoded samples.
Return Value
------------
Returns the number of PCM frames actually read. If the return value is less than `framesToRead` it has reached the end.
Remarks
-------
pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of frames seeked.
Note that this is lossy for streams where the bits per sample is larger than 16.
*/
DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s16(drflac* pFlac, drflac_uint64 framesToRead, drflac_int16* pBufferOut);
/*
Reads sample data from the given FLAC decoder, output as interleaved 32-bit floating point PCM.
Parameters
----------
pFlac (in)
The decoder.
framesToRead (in)
The number of PCM frames to read.
pBufferOut (out, optional)
A pointer to the buffer that will receive the decoded samples.
Return Value
------------
Returns the number of PCM frames actually read. If the return value is less than `framesToRead` it has reached the end.
Remarks
-------
pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of frames seeked.
Note that this should be considered lossy due to the nature of floating point numbers not being able to exactly represent every possible number.
*/
DRFLAC_API drflac_uint64 drflac_read_pcm_frames_f32(drflac* pFlac, drflac_uint64 framesToRead, float* pBufferOut);
/*
Seeks to the PCM frame at the given index.
Parameters
----------
pFlac (in)
The decoder.
pcmFrameIndex (in)
The index of the PCM frame to seek to. See notes below.
Return Value
-------------
`DRFLAC_TRUE` if successful; `DRFLAC_FALSE` otherwise.
*/
DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex);
#ifndef DR_FLAC_NO_STDIO
/*
Opens a FLAC decoder from the file at the given path.
Parameters
----------
pFileName (in)
The path of the file to open, either absolute or relative to the current directory.
pAllocationCallbacks (in, optional)
A pointer to application defined callbacks for managing memory allocations.
Return Value
------------
A pointer to an object representing the decoder.
Remarks
-------
Close the decoder with drflac_close().
Remarks
-------
This will hold a handle to the file until the decoder is closed with drflac_close(). Some platforms will restrict the number of files a process can have open
at any given time, so keep this mind if you have many decoders open at the same time.
See Also
--------
drflac_open_file_with_metadata()
drflac_open()
drflac_close()
*/
DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks);
DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks);
/*
Opens a FLAC decoder from the file at the given path and notifies the caller of the metadata chunks (album art, etc.)
Parameters
----------
pFileName (in)
The path of the file to open, either absolute or relative to the current directory.
pAllocationCallbacks (in, optional)
A pointer to application defined callbacks for managing memory allocations.
onMeta (in)
The callback to fire for each metadata block.
pUserData (in)
A pointer to the user data to pass to the metadata callback.
share/public_html/static/music_inc/src/dr_flac.h view on Meta::CPAN
See Also
--------
drflac_open()
drflac_close()
*/
DRFLAC_API drflac* drflac_open_memory(const void* pData, size_t dataSize, const drflac_allocation_callbacks* pAllocationCallbacks);
/*
Opens a FLAC decoder from a pre-allocated block of memory and notifies the caller of the metadata chunks (album art, etc.)
Parameters
----------
pData (in)
A pointer to the raw encoded FLAC data.
dataSize (in)
The size in bytes of `data`.
onMeta (in)
The callback to fire for each metadata block.
pUserData (in)
A pointer to the user data to pass to the metadata callback.
pAllocationCallbacks (in)
A pointer to application defined callbacks for managing memory allocations.
Remarks
-------
Look at the documentation for drflac_open_with_metadata() for more information on how metadata is handled.
See Also
-------
drflac_open_with_metadata()
drflac_open()
drflac_close()
*/
DRFLAC_API drflac* drflac_open_memory_with_metadata(const void* pData, size_t dataSize, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
/* High Level APIs */
/*
Opens a FLAC stream from the given callbacks and fully decodes it in a single operation. The return value is a
pointer to the sample data as interleaved signed 32-bit PCM. The returned data must be freed with drflac_free().
You can pass in custom memory allocation callbacks via the pAllocationCallbacks parameter. This can be NULL in which
case it will use DRFLAC_MALLOC, DRFLAC_REALLOC and DRFLAC_FREE.
Sometimes a FLAC file won't keep track of the total sample count. In this situation the function will continuously
read samples into a dynamically sized buffer on the heap until no samples are left.
Do not call this function on a broadcast type of stream (like internet radio streams and whatnot).
*/
DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pA...
/* Same as drflac_open_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. */
DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pA...
/* Same as drflac_open_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. */
DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocati...
#ifndef DR_FLAC_NO_STDIO
/* Same as drflac_open_and_read_pcm_frames_s32() except opens the decoder from a file. */
DRFLAC_API drflac_int32* drflac_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
/* Same as drflac_open_file_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. */
DRFLAC_API drflac_int16* drflac_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
/* Same as drflac_open_file_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. */
DRFLAC_API float* drflac_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
#endif
/* Same as drflac_open_and_read_pcm_frames_s32() except opens the decoder from a block of memory. */
DRFLAC_API drflac_int32* drflac_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
/* Same as drflac_open_memory_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. */
DRFLAC_API drflac_int16* drflac_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
/* Same as drflac_open_memory_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. */
DRFLAC_API float* drflac_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
/*
Frees memory that was allocated internally by dr_flac.
Set pAllocationCallbacks to the same object that was passed to drflac_open_*_and_read_pcm_frames_*(). If you originally passed in NULL, pass in NULL for this.
*/
DRFLAC_API void drflac_free(void* p, const drflac_allocation_callbacks* pAllocationCallbacks);
/* Structure representing an iterator for vorbis comments in a VORBIS_COMMENT metadata block. */
typedef struct
{
drflac_uint32 countRemaining;
const char* pRunningData;
} drflac_vorbis_comment_iterator;
/*
Initializes a vorbis comment iterator. This can be used for iterating over the vorbis comments in a VORBIS_COMMENT
metadata block.
*/
DRFLAC_API void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const void* pComments);
/*
Goes to the next vorbis comment in the given iterator. If null is returned it means there are no more comments. The
returned string is NOT null terminated.
*/
DRFLAC_API const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut);
/* Structure representing an iterator for cuesheet tracks in a CUESHEET metadata block. */
typedef struct
{
drflac_uint32 countRemaining;
const char* pRunningData;
} drflac_cuesheet_track_iterator;
/* Packing is important on this structure because we map this directly to the raw data within the CUESHEET metadata block. */
#pragma pack(4)
typedef struct
{
drflac_uint64 offset;
drflac_uint8 index;
drflac_uint8 reserved[3];
} drflac_cuesheet_track_index;
#pragma pack()
typedef struct
{
drflac_uint64 offset;
drflac_uint8 trackNumber;
char ISRC[12];
drflac_bool8 isAudio;
drflac_bool8 preEmphasis;
drflac_uint8 indexCount;
const drflac_cuesheet_track_index* pIndexPoints;
} drflac_cuesheet_track;
/*
Initializes a cuesheet track iterator. This can be used for iterating over the cuesheet tracks in a CUESHEET metadata
block.
*/
DRFLAC_API void drflac_init_cuesheet_track_iterator(drflac_cuesheet_track_iterator* pIter, drflac_uint32 trackCount, const void* pTrackData);
/* Goes to the next cuesheet track in the given iterator. If DRFLAC_FALSE is returned it means there are no more comments. */
DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter, drflac_cuesheet_track* pCuesheetTrack);
share/public_html/static/music_inc/src/dr_flac.h view on Meta::CPAN
*pResult = (drflac_int8)result;
return DRFLAC_TRUE;
}
static drflac_bool32 drflac__seek_bits(drflac_bs* bs, size_t bitsToSeek)
{
if (bitsToSeek <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
bs->consumedBits += (drflac_uint32)bitsToSeek;
bs->cache <<= bitsToSeek;
return DRFLAC_TRUE;
} else {
/* It straddles the cached data. This function isn't called too frequently so I'm favouring simplicity here. */
bitsToSeek -= DRFLAC_CACHE_L1_BITS_REMAINING(bs);
bs->consumedBits += DRFLAC_CACHE_L1_BITS_REMAINING(bs);
bs->cache = 0;
/* Simple case. Seek in groups of the same number as bits that fit within a cache line. */
#ifdef DRFLAC_64BIT
while (bitsToSeek >= DRFLAC_CACHE_L1_SIZE_BITS(bs)) {
drflac_uint64 bin;
if (!drflac__read_uint64(bs, DRFLAC_CACHE_L1_SIZE_BITS(bs), &bin)) {
return DRFLAC_FALSE;
}
bitsToSeek -= DRFLAC_CACHE_L1_SIZE_BITS(bs);
}
#else
while (bitsToSeek >= DRFLAC_CACHE_L1_SIZE_BITS(bs)) {
drflac_uint32 bin;
if (!drflac__read_uint32(bs, DRFLAC_CACHE_L1_SIZE_BITS(bs), &bin)) {
return DRFLAC_FALSE;
}
bitsToSeek -= DRFLAC_CACHE_L1_SIZE_BITS(bs);
}
#endif
/* Whole leftover bytes. */
while (bitsToSeek >= 8) {
drflac_uint8 bin;
if (!drflac__read_uint8(bs, 8, &bin)) {
return DRFLAC_FALSE;
}
bitsToSeek -= 8;
}
/* Leftover bits. */
if (bitsToSeek > 0) {
drflac_uint8 bin;
if (!drflac__read_uint8(bs, (drflac_uint32)bitsToSeek, &bin)) {
return DRFLAC_FALSE;
}
bitsToSeek = 0; /* <-- Necessary for the assert below. */
}
DRFLAC_ASSERT(bitsToSeek == 0);
return DRFLAC_TRUE;
}
}
/* This function moves the bit streamer to the first bit after the sync code (bit 15 of the of the frame header). It will also update the CRC-16. */
static drflac_bool32 drflac__find_and_seek_to_next_sync_code(drflac_bs* bs)
{
DRFLAC_ASSERT(bs != NULL);
/*
The sync code is always aligned to 8 bits. This is convenient for us because it means we can do byte-aligned movements. The first
thing to do is align to the next byte.
*/
if (!drflac__seek_bits(bs, DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7)) {
return DRFLAC_FALSE;
}
for (;;) {
drflac_uint8 hi;
#ifndef DR_FLAC_NO_CRC
drflac__reset_crc16(bs);
#endif
if (!drflac__read_uint8(bs, 8, &hi)) {
return DRFLAC_FALSE;
}
if (hi == 0xFF) {
drflac_uint8 lo;
if (!drflac__read_uint8(bs, 6, &lo)) {
return DRFLAC_FALSE;
}
if (lo == 0x3E) {
return DRFLAC_TRUE;
} else {
if (!drflac__seek_bits(bs, DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7)) {
return DRFLAC_FALSE;
}
}
}
}
/* Should never get here. */
/*return DRFLAC_FALSE;*/
}
#if defined(DRFLAC_HAS_LZCNT_INTRINSIC)
#define DRFLAC_IMPLEMENT_CLZ_LZCNT
#endif
#if defined(_MSC_VER) && _MSC_VER >= 1400 && (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(__clang__)
#define DRFLAC_IMPLEMENT_CLZ_MSVC
#endif
static DRFLAC_INLINE drflac_uint32 drflac__clz_software(drflac_cache_t x)
{
drflac_uint32 n;
static drflac_uint32 clz_table_4[] = {
0,
4,
3, 3,
2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1
share/public_html/static/music_inc/src/dr_flac.h view on Meta::CPAN
return drflac__decode_samples_with_residual__rice__neon(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut);
} else
#endif
{
/* Scalar fallback. */
#if 0
return drflac__decode_samples_with_residual__rice__reference(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut);
#else
return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut);
#endif
}
}
/* Reads and seeks past a string of residual values as Rice codes. The decoder should be sitting on the first bit of the Rice codes. */
static drflac_bool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam)
{
drflac_uint32 i;
DRFLAC_ASSERT(bs != NULL);
DRFLAC_ASSERT(count > 0);
for (i = 0; i < count; ++i) {
if (!drflac__seek_rice_parts(bs, riceParam)) {
return DRFLAC_FALSE;
}
}
return DRFLAC_TRUE;
}
static drflac_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 unencodedBitsPerSample, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drfl...
{
drflac_uint32 i;
DRFLAC_ASSERT(bs != NULL);
DRFLAC_ASSERT(count > 0);
DRFLAC_ASSERT(unencodedBitsPerSample <= 31); /* <-- unencodedBitsPerSample is a 5 bit number, so cannot exceed 31. */
DRFLAC_ASSERT(pSamplesOut != NULL);
for (i = 0; i < count; ++i) {
if (unencodedBitsPerSample > 0) {
if (!drflac__read_int32(bs, unencodedBitsPerSample, pSamplesOut + i)) {
return DRFLAC_FALSE;
}
} else {
pSamplesOut[i] = 0;
}
if (bitsPerSample >= 24) {
pSamplesOut[i] += drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + i);
} else {
pSamplesOut[i] += drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + i);
}
}
return DRFLAC_TRUE;
}
/*
Reads and decodes the residual for the sub-frame the decoder is currently sitting on. This function should be called
when the decoder is sitting at the very start of the RESIDUAL block. The first <order> residuals will be ignored. The
<blockSize> and <order> parameters are used to determine how many residual values need to be decoded.
*/
static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 blockSize, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples)
{
drflac_uint8 residualMethod;
drflac_uint8 partitionOrder;
drflac_uint32 samplesInPartition;
drflac_uint32 partitionsRemaining;
DRFLAC_ASSERT(bs != NULL);
DRFLAC_ASSERT(blockSize != 0);
DRFLAC_ASSERT(pDecodedSamples != NULL); /* <-- Should we allow NULL, in which case we just seek past the residual rather than do a full decode? */
if (!drflac__read_uint8(bs, 2, &residualMethod)) {
return DRFLAC_FALSE;
}
if (residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
return DRFLAC_FALSE; /* Unknown or unsupported residual coding method. */
}
/* Ignore the first <order> values. */
pDecodedSamples += order;
if (!drflac__read_uint8(bs, 4, &partitionOrder)) {
return DRFLAC_FALSE;
}
/*
From the FLAC spec:
The Rice partition order in a Rice-coded residual section must be less than or equal to 8.
*/
if (partitionOrder > 8) {
return DRFLAC_FALSE;
}
/* Validation check. */
if ((blockSize / (1 << partitionOrder)) <= order) {
return DRFLAC_FALSE;
}
samplesInPartition = (blockSize / (1 << partitionOrder)) - order;
partitionsRemaining = (1 << partitionOrder);
for (;;) {
drflac_uint8 riceParam = 0;
if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) {
if (!drflac__read_uint8(bs, 4, &riceParam)) {
return DRFLAC_FALSE;
}
if (riceParam == 15) {
riceParam = 0xFF;
}
} else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
if (!drflac__read_uint8(bs, 5, &riceParam)) {
return DRFLAC_FALSE;
}
if (riceParam == 31) {
riceParam = 0xFF;
}
}
if (riceParam != 0xFF) {
if (!drflac__decode_samples_with_residual__rice(bs, bitsPerSample, samplesInPartition, riceParam, order, shift, coefficients, pDecodedSamples)) {
return DRFLAC_FALSE;
}
} else {
drflac_uint8 unencodedBitsPerSample = 0;
if (!drflac__read_uint8(bs, 5, &unencodedBitsPerSample)) {
return DRFLAC_FALSE;
}
if (!drflac__decode_samples_with_residual__unencoded(bs, bitsPerSample, samplesInPartition, unencodedBitsPerSample, order, shift, coefficients, pDecodedSamples)) {
return DRFLAC_FALSE;
}
}
pDecodedSamples += samplesInPartition;
if (partitionsRemaining == 1) {
break;
}
partitionsRemaining -= 1;
if (partitionOrder != 0) {
samplesInPartition = blockSize / (1 << partitionOrder);
}
}
return DRFLAC_TRUE;
}
/*
Reads and seeks past the residual for the sub-frame the decoder is currently sitting on. This function should be called
when the decoder is sitting at the very start of the RESIDUAL block. The first <order> residuals will be set to 0. The
<blockSize> and <order> parameters are used to determine how many residual values need to be decoded.
*/
static drflac_bool32 drflac__read_and_seek_residual(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 order)
{
drflac_uint8 residualMethod;
drflac_uint8 partitionOrder;
drflac_uint32 samplesInPartition;
drflac_uint32 partitionsRemaining;
DRFLAC_ASSERT(bs != NULL);
DRFLAC_ASSERT(blockSize != 0);
if (!drflac__read_uint8(bs, 2, &residualMethod)) {
return DRFLAC_FALSE;
}
if (residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
return DRFLAC_FALSE; /* Unknown or unsupported residual coding method. */
}
if (!drflac__read_uint8(bs, 4, &partitionOrder)) {
return DRFLAC_FALSE;
}
/*
From the FLAC spec:
The Rice partition order in a Rice-coded residual section must be less than or equal to 8.
*/
if (partitionOrder > 8) {
return DRFLAC_FALSE;
}
/* Validation check. */
if ((blockSize / (1 << partitionOrder)) <= order) {
return DRFLAC_FALSE;
}
samplesInPartition = (blockSize / (1 << partitionOrder)) - order;
partitionsRemaining = (1 << partitionOrder);
for (;;)
{
drflac_uint8 riceParam = 0;
if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) {
if (!drflac__read_uint8(bs, 4, &riceParam)) {
return DRFLAC_FALSE;
}
if (riceParam == 15) {
riceParam = 0xFF;
}
} else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
if (!drflac__read_uint8(bs, 5, &riceParam)) {
return DRFLAC_FALSE;
}
if (riceParam == 31) {
riceParam = 0xFF;
}
}
if (riceParam != 0xFF) {
if (!drflac__read_and_seek_residual__rice(bs, samplesInPartition, riceParam)) {
return DRFLAC_FALSE;
}
} else {
drflac_uint8 unencodedBitsPerSample = 0;
if (!drflac__read_uint8(bs, 5, &unencodedBitsPerSample)) {
return DRFLAC_FALSE;
}
if (!drflac__seek_bits(bs, unencodedBitsPerSample * samplesInPartition)) {
return DRFLAC_FALSE;
}
}
if (partitionsRemaining == 1) {
break;
}
partitionsRemaining -= 1;
samplesInPartition = blockSize / (1 << partitionOrder);
}
return DRFLAC_TRUE;
}
static drflac_bool32 drflac__decode_samples__constant(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_int32* pDecodedSamples)
{
drflac_uint32 i;
/* Only a single sample needs to be decoded here. */
drflac_int32 sample;
if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) {
return DRFLAC_FALSE;
}
/*
We don't really need to expand this, but it does simplify the process of reading samples. If this becomes a performance issue (unlikely)
we'll want to look at a more efficient way.
*/
for (i = 0; i < blockSize; ++i) {
pDecodedSamples[i] = sample;
}
return DRFLAC_TRUE;
}
static drflac_bool32 drflac__decode_samples__verbatim(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_int32* pDecodedSamples)
{
drflac_uint32 i;
for (i = 0; i < blockSize; ++i) {
drflac_int32 sample;
if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) {
return DRFLAC_FALSE;
}
pDecodedSamples[i] = sample;
}
return DRFLAC_TRUE;
}
static drflac_bool32 drflac__decode_samples__fixed(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_uint8 lpcOrder, drflac_int32* pDecodedSamples)
{
drflac_uint32 i;
static drflac_int32 lpcCoefficientsTable[5][4] = {
{0, 0, 0, 0},
{1, 0, 0, 0},
{2, -1, 0, 0},
{3, -3, 1, 0},
{4, -6, 4, -1}
};
/* Warm up samples and coefficients. */
for (i = 0; i < lpcOrder; ++i) {
drflac_int32 sample;
if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) {
return DRFLAC_FALSE;
}
pDecodedSamples[i] = sample;
}
if (!drflac__decode_samples_with_residual(bs, subframeBitsPerSample, blockSize, lpcOrder, 0, lpcCoefficientsTable[lpcOrder], pDecodedSamples)) {
return DRFLAC_FALSE;
}
return DRFLAC_TRUE;
}
static drflac_bool32 drflac__decode_samples__lpc(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 bitsPerSample, drflac_uint8 lpcOrder, drflac_int32* pDecodedSamples)
{
drflac_uint8 i;
drflac_uint8 lpcPrecision;
drflac_int8 lpcShift;
drflac_int32 coefficients[32];
/* Warm up samples. */
for (i = 0; i < lpcOrder; ++i) {
drflac_int32 sample;
if (!drflac__read_int32(bs, bitsPerSample, &sample)) {
return DRFLAC_FALSE;
}
pDecodedSamples[i] = sample;
}
if (!drflac__read_uint8(bs, 4, &lpcPrecision)) {
return DRFLAC_FALSE;
}
if (lpcPrecision == 15) {
return DRFLAC_FALSE; /* Invalid. */
}
lpcPrecision += 1;
if (!drflac__read_int8(bs, 5, &lpcShift)) {
return DRFLAC_FALSE;
}
/*
From the FLAC specification:
Quantized linear predictor coefficient shift needed in bits (NOTE: this number is signed two's-complement)
Emphasis on the "signed two's-complement". In practice there does not seem to be any encoders nor decoders supporting negative shifts. For now dr_flac is
not going to support negative shifts as I don't have any reference files. However, when a reference file comes through I will consider adding support.
*/
if (lpcShift < 0) {
return DRFLAC_FALSE;
}
DRFLAC_ZERO_MEMORY(coefficients, sizeof(coefficients));
for (i = 0; i < lpcOrder; ++i) {
if (!drflac__read_int32(bs, lpcPrecision, coefficients + i)) {
return DRFLAC_FALSE;
}
}
if (!drflac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, lpcShift, coefficients, pDecodedSamples)) {
return DRFLAC_FALSE;
}
return DRFLAC_TRUE;
}
static drflac_bool32 drflac__read_next_flac_frame_header(drflac_bs* bs, drflac_uint8 streaminfoBitsPerSample, drflac_frame_header* header)
{
const drflac_uint32 sampleRateTable[12] = {0, 88200, 176400, 192000, 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000};
const drflac_uint8 bitsPerSampleTable[8] = {0, 8, 12, (drflac_uint8)-1, 16, 20, 24, (drflac_uint8)-1}; /* -1 = reserved. */
DRFLAC_ASSERT(bs != NULL);
DRFLAC_ASSERT(header != NULL);
/* Keep looping until we find a valid sync code. */
for (;;) {
drflac_uint8 crc8 = 0xCE; /* 0xCE = drflac_crc8(0, 0x3FFE, 14); */
drflac_uint8 reserved = 0;
drflac_uint8 blockingStrategy = 0;
drflac_uint8 blockSize = 0;
drflac_uint8 sampleRate = 0;
drflac_uint8 channelAssignment = 0;
drflac_uint8 bitsPerSample = 0;
drflac_bool32 isVariableBlockSize;
if (!drflac__find_and_seek_to_next_sync_code(bs)) {
return DRFLAC_FALSE;
}
if (!drflac__read_uint8(bs, 1, &reserved)) {
return DRFLAC_FALSE;
}
if (reserved == 1) {
continue;
}
crc8 = drflac_crc8(crc8, reserved, 1);
if (!drflac__read_uint8(bs, 1, &blockingStrategy)) {
return DRFLAC_FALSE;
}
crc8 = drflac_crc8(crc8, blockingStrategy, 1);
if (!drflac__read_uint8(bs, 4, &blockSize)) {
return DRFLAC_FALSE;
}
if (blockSize == 0) {
continue;
}
crc8 = drflac_crc8(crc8, blockSize, 4);
if (!drflac__read_uint8(bs, 4, &sampleRate)) {
return DRFLAC_FALSE;
}
crc8 = drflac_crc8(crc8, sampleRate, 4);
if (!drflac__read_uint8(bs, 4, &channelAssignment)) {
return DRFLAC_FALSE;
}
if (channelAssignment > 10) {
continue;
}
crc8 = drflac_crc8(crc8, channelAssignment, 4);
if (!drflac__read_uint8(bs, 3, &bitsPerSample)) {
return DRFLAC_FALSE;
}
if (bitsPerSample == 3 || bitsPerSample == 7) {
share/public_html/static/music_inc/src/dr_flac.h view on Meta::CPAN
return DRFLAC_FALSE;
}
crc8 = drflac_crc8(crc8, header->blockSizeInPCMFrames, 8);
header->blockSizeInPCMFrames += 1;
} else if (blockSize == 7) {
if (!drflac__read_uint16(bs, 16, &header->blockSizeInPCMFrames)) {
return DRFLAC_FALSE;
}
crc8 = drflac_crc8(crc8, header->blockSizeInPCMFrames, 16);
header->blockSizeInPCMFrames += 1;
} else {
DRFLAC_ASSERT(blockSize >= 8);
header->blockSizeInPCMFrames = 256 * (1 << (blockSize - 8));
}
if (sampleRate <= 11) {
header->sampleRate = sampleRateTable[sampleRate];
} else if (sampleRate == 12) {
if (!drflac__read_uint32(bs, 8, &header->sampleRate)) {
return DRFLAC_FALSE;
}
crc8 = drflac_crc8(crc8, header->sampleRate, 8);
header->sampleRate *= 1000;
} else if (sampleRate == 13) {
if (!drflac__read_uint32(bs, 16, &header->sampleRate)) {
return DRFLAC_FALSE;
}
crc8 = drflac_crc8(crc8, header->sampleRate, 16);
} else if (sampleRate == 14) {
if (!drflac__read_uint32(bs, 16, &header->sampleRate)) {
return DRFLAC_FALSE;
}
crc8 = drflac_crc8(crc8, header->sampleRate, 16);
header->sampleRate *= 10;
} else {
continue; /* Invalid. Assume an invalid block. */
}
header->channelAssignment = channelAssignment;
header->bitsPerSample = bitsPerSampleTable[bitsPerSample];
if (header->bitsPerSample == 0) {
header->bitsPerSample = streaminfoBitsPerSample;
}
if (!drflac__read_uint8(bs, 8, &header->crc8)) {
return DRFLAC_FALSE;
}
#ifndef DR_FLAC_NO_CRC
if (header->crc8 != crc8) {
continue; /* CRC mismatch. Loop back to the top and find the next sync code. */
}
#endif
return DRFLAC_TRUE;
}
}
static drflac_bool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe* pSubframe)
{
drflac_uint8 header;
int type;
if (!drflac__read_uint8(bs, 8, &header)) {
return DRFLAC_FALSE;
}
/* First bit should always be 0. */
if ((header & 0x80) != 0) {
return DRFLAC_FALSE;
}
type = (header & 0x7E) >> 1;
if (type == 0) {
pSubframe->subframeType = DRFLAC_SUBFRAME_CONSTANT;
} else if (type == 1) {
pSubframe->subframeType = DRFLAC_SUBFRAME_VERBATIM;
} else {
if ((type & 0x20) != 0) {
pSubframe->subframeType = DRFLAC_SUBFRAME_LPC;
pSubframe->lpcOrder = (drflac_uint8)(type & 0x1F) + 1;
} else if ((type & 0x08) != 0) {
pSubframe->subframeType = DRFLAC_SUBFRAME_FIXED;
pSubframe->lpcOrder = (drflac_uint8)(type & 0x07);
if (pSubframe->lpcOrder > 4) {
pSubframe->subframeType = DRFLAC_SUBFRAME_RESERVED;
pSubframe->lpcOrder = 0;
}
} else {
pSubframe->subframeType = DRFLAC_SUBFRAME_RESERVED;
}
}
if (pSubframe->subframeType == DRFLAC_SUBFRAME_RESERVED) {
return DRFLAC_FALSE;
}
/* Wasted bits per sample. */
pSubframe->wastedBitsPerSample = 0;
if ((header & 0x01) == 1) {
unsigned int wastedBitsPerSample;
if (!drflac__seek_past_next_set_bit(bs, &wastedBitsPerSample)) {
return DRFLAC_FALSE;
}
pSubframe->wastedBitsPerSample = (drflac_uint8)wastedBitsPerSample + 1;
}
return DRFLAC_TRUE;
}
static drflac_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex, drflac_int32* pDecodedSamplesOut)
{
drflac_subframe* pSubframe;
drflac_uint32 subframeBitsPerSample;
DRFLAC_ASSERT(bs != NULL);
DRFLAC_ASSERT(frame != NULL);
pSubframe = frame->subframes + subframeIndex;
if (!drflac__read_subframe_header(bs, pSubframe)) {
return DRFLAC_FALSE;
}
/* Side channels require an extra bit per sample. Took a while to figure that one out... */
subframeBitsPerSample = frame->header.bitsPerSample;
if ((frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) {
subframeBitsPerSample += 1;
} else if (frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) {
subframeBitsPerSample += 1;
}
/* Need to handle wasted bits per sample. */
if (pSubframe->wastedBitsPerSample >= subframeBitsPerSample) {
return DRFLAC_FALSE;
}
subframeBitsPerSample -= pSubframe->wastedBitsPerSample;
pSubframe->pSamplesS32 = pDecodedSamplesOut;
switch (pSubframe->subframeType)
{
case DRFLAC_SUBFRAME_CONSTANT:
{
drflac__decode_samples__constant(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->pSamplesS32);
} break;
case DRFLAC_SUBFRAME_VERBATIM:
{
drflac__decode_samples__verbatim(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->pSamplesS32);
} break;
case DRFLAC_SUBFRAME_FIXED:
{
drflac__decode_samples__fixed(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->lpcOrder, pSubframe->pSamplesS32);
} break;
case DRFLAC_SUBFRAME_LPC:
{
drflac__decode_samples__lpc(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->lpcOrder, pSubframe->pSamplesS32);
} break;
default: return DRFLAC_FALSE;
}
return DRFLAC_TRUE;
}
static drflac_bool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex)
{
drflac_subframe* pSubframe;
drflac_uint32 subframeBitsPerSample;
DRFLAC_ASSERT(bs != NULL);
DRFLAC_ASSERT(frame != NULL);
pSubframe = frame->subframes + subframeIndex;
if (!drflac__read_subframe_header(bs, pSubframe)) {
return DRFLAC_FALSE;
}
/* Side channels require an extra bit per sample. Took a while to figure that one out... */
subframeBitsPerSample = frame->header.bitsPerSample;
if ((frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) {
subframeBitsPerSample += 1;
} else if (frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) {
subframeBitsPerSample += 1;
}
/* Need to handle wasted bits per sample. */
if (pSubframe->wastedBitsPerSample >= subframeBitsPerSample) {
return DRFLAC_FALSE;
}
subframeBitsPerSample -= pSubframe->wastedBitsPerSample;
pSubframe->pSamplesS32 = NULL;
switch (pSubframe->subframeType)
{
case DRFLAC_SUBFRAME_CONSTANT:
{
if (!drflac__seek_bits(bs, subframeBitsPerSample)) {
return DRFLAC_FALSE;
}
} break;
case DRFLAC_SUBFRAME_VERBATIM:
{
unsigned int bitsToSeek = frame->header.blockSizeInPCMFrames * subframeBitsPerSample;
if (!drflac__seek_bits(bs, bitsToSeek)) {
return DRFLAC_FALSE;
}
} break;
case DRFLAC_SUBFRAME_FIXED:
{
unsigned int bitsToSeek = pSubframe->lpcOrder * subframeBitsPerSample;
if (!drflac__seek_bits(bs, bitsToSeek)) {
return DRFLAC_FALSE;
}
if (!drflac__read_and_seek_residual(bs, frame->header.blockSizeInPCMFrames, pSubframe->lpcOrder)) {
return DRFLAC_FALSE;
}
} break;
case DRFLAC_SUBFRAME_LPC:
{
drflac_uint8 lpcPrecision;
unsigned int bitsToSeek = pSubframe->lpcOrder * subframeBitsPerSample;
if (!drflac__seek_bits(bs, bitsToSeek)) {
return DRFLAC_FALSE;
}
if (!drflac__read_uint8(bs, 4, &lpcPrecision)) {
return DRFLAC_FALSE;
}
if (lpcPrecision == 15) {
return DRFLAC_FALSE; /* Invalid. */
}
lpcPrecision += 1;
bitsToSeek = (pSubframe->lpcOrder * lpcPrecision) + 5; /* +5 for shift. */
if (!drflac__seek_bits(bs, bitsToSeek)) {
return DRFLAC_FALSE;
}
if (!drflac__read_and_seek_residual(bs, frame->header.blockSizeInPCMFrames, pSubframe->lpcOrder)) {
return DRFLAC_FALSE;
}
} break;
default: return DRFLAC_FALSE;
}
return DRFLAC_TRUE;
}
static DRFLAC_INLINE drflac_uint8 drflac__get_channel_count_from_channel_assignment(drflac_int8 channelAssignment)
{
drflac_uint8 lookup[] = {1, 2, 3, 4, 5, 6, 7, 8, 2, 2, 2};
DRFLAC_ASSERT(channelAssignment <= 10);
return lookup[channelAssignment];
}
static drflac_result drflac__decode_flac_frame(drflac* pFlac)
{
int channelCount;
int i;
drflac_uint8 paddingSizeInBits;
drflac_uint16 desiredCRC16;
#ifndef DR_FLAC_NO_CRC
drflac_uint16 actualCRC16;
#endif
/* This function should be called while the stream is sitting on the first byte after the frame header. */
DRFLAC_ZERO_MEMORY(pFlac->currentFLACFrame.subframes, sizeof(pFlac->currentFLACFrame.subframes));
/* The frame block size must never be larger than the maximum block size defined by the FLAC stream. */
if (pFlac->currentFLACFrame.header.blockSizeInPCMFrames > pFlac->maxBlockSizeInPCMFrames) {
return DRFLAC_ERROR;
}
/* The number of channels in the frame must match the channel count from the STREAMINFO block. */
channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment);
if (channelCount != (int)pFlac->channels) {
return DRFLAC_ERROR;
}
for (i = 0; i < channelCount; ++i) {
if (!drflac__decode_subframe(&pFlac->bs, &pFlac->currentFLACFrame, i, pFlac->pDecodedSamples + (pFlac->currentFLACFrame.header.blockSizeInPCMFrames * i))) {
return DRFLAC_ERROR;
}
}
paddingSizeInBits = (drflac_uint8)(DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7);
if (paddingSizeInBits > 0) {
drflac_uint8 padding = 0;
if (!drflac__read_uint8(&pFlac->bs, paddingSizeInBits, &padding)) {
return DRFLAC_AT_END;
}
}
#ifndef DR_FLAC_NO_CRC
actualCRC16 = drflac__flush_crc16(&pFlac->bs);
#endif
if (!drflac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) {
return DRFLAC_AT_END;
}
#ifndef DR_FLAC_NO_CRC
if (actualCRC16 != desiredCRC16) {
return DRFLAC_CRC_MISMATCH; /* CRC mismatch. */
}
#endif
pFlac->currentFLACFrame.pcmFramesRemaining = pFlac->currentFLACFrame.header.blockSizeInPCMFrames;
return DRFLAC_SUCCESS;
}
static drflac_result drflac__seek_flac_frame(drflac* pFlac)
{
int channelCount;
int i;
drflac_uint16 desiredCRC16;
#ifndef DR_FLAC_NO_CRC
drflac_uint16 actualCRC16;
#endif
channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment);
for (i = 0; i < channelCount; ++i) {
if (!drflac__seek_subframe(&pFlac->bs, &pFlac->currentFLACFrame, i)) {
return DRFLAC_ERROR;
}
}
/* Padding. */
if (!drflac__seek_bits(&pFlac->bs, DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7)) {
return DRFLAC_ERROR;
}
/* CRC. */
#ifndef DR_FLAC_NO_CRC
actualCRC16 = drflac__flush_crc16(&pFlac->bs);
#endif
if (!drflac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) {
return DRFLAC_AT_END;
}
#ifndef DR_FLAC_NO_CRC
if (actualCRC16 != desiredCRC16) {
return DRFLAC_CRC_MISMATCH; /* CRC mismatch. */
}
#endif
return DRFLAC_SUCCESS;
}
static drflac_bool32 drflac__read_and_decode_next_flac_frame(drflac* pFlac)
{
DRFLAC_ASSERT(pFlac != NULL);
for (;;) {
drflac_result result;
if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
return DRFLAC_FALSE;
}
result = drflac__decode_flac_frame(pFlac);
if (result != DRFLAC_SUCCESS) {
if (result == DRFLAC_CRC_MISMATCH) {
continue; /* CRC mismatch. Skip to the next frame. */
} else {
return DRFLAC_FALSE;
}
}
return DRFLAC_TRUE;
}
}
static void drflac__get_pcm_frame_range_of_current_flac_frame(drflac* pFlac, drflac_uint64* pFirstPCMFrame, drflac_uint64* pLastPCMFrame)
{
drflac_uint64 firstPCMFrame;
drflac_uint64 lastPCMFrame;
DRFLAC_ASSERT(pFlac != NULL);
firstPCMFrame = pFlac->currentFLACFrame.header.pcmFrameNumber;
if (firstPCMFrame == 0) {
firstPCMFrame = ((drflac_uint64)pFlac->currentFLACFrame.header.flacFrameNumber) * pFlac->maxBlockSizeInPCMFrames;
}
lastPCMFrame = firstPCMFrame + pFlac->currentFLACFrame.header.blockSizeInPCMFrames;
if (lastPCMFrame > 0) {
lastPCMFrame -= 1; /* Needs to be zero based. */
}
if (pFirstPCMFrame) {
*pFirstPCMFrame = firstPCMFrame;
}
if (pLastPCMFrame) {
*pLastPCMFrame = lastPCMFrame;
}
}
static drflac_bool32 drflac__seek_to_first_frame(drflac* pFlac)
{
drflac_bool32 result;
DRFLAC_ASSERT(pFlac != NULL);
result = drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes);
DRFLAC_ZERO_MEMORY(&pFlac->currentFLACFrame, sizeof(pFlac->currentFLACFrame));
pFlac->currentPCMFrame = 0;
return result;
}
static DRFLAC_INLINE drflac_result drflac__seek_to_next_flac_frame(drflac* pFlac)
{
/* This function should only ever be called while the decoder is sitting on the first byte past the FRAME_HEADER section. */
DRFLAC_ASSERT(pFlac != NULL);
return drflac__seek_flac_frame(pFlac);
}
static drflac_uint64 drflac__seek_forward_by_pcm_frames(drflac* pFlac, drflac_uint64 pcmFramesToSeek)
{
drflac_uint64 pcmFramesRead = 0;
while (pcmFramesToSeek > 0) {
if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
if (!drflac__read_and_decode_next_flac_frame(pFlac)) {
break; /* Couldn't read the next frame, so just break from the loop and return. */
}
} else {
if (pFlac->currentFLACFrame.pcmFramesRemaining > pcmFramesToSeek) {
pcmFramesRead += pcmFramesToSeek;
pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)pcmFramesToSeek; /* <-- Safe cast. Will always be < currentFrame.pcmFramesRemaining < 65536. */
pcmFramesToSeek = 0;
} else {
pcmFramesRead += pFlac->currentFLACFrame.pcmFramesRemaining;
pcmFramesToSeek -= pFlac->currentFLACFrame.pcmFramesRemaining;
pFlac->currentFLACFrame.pcmFramesRemaining = 0;
}
}
}
pFlac->currentPCMFrame += pcmFramesRead;
return pcmFramesRead;
}
static drflac_bool32 drflac__seek_to_pcm_frame__brute_force(drflac* pFlac, drflac_uint64 pcmFrameIndex)
{
drflac_bool32 isMidFrame = DRFLAC_FALSE;
drflac_uint64 runningPCMFrameCount;
DRFLAC_ASSERT(pFlac != NULL);
/* If we are seeking forward we start from the current position. Otherwise we need to start all the way from the start of the file. */
if (pcmFrameIndex >= pFlac->currentPCMFrame) {
/* Seeking forward. Need to seek from the current position. */
runningPCMFrameCount = pFlac->currentPCMFrame;
/* The frame header for the first frame may not yet have been read. We need to do that if necessary. */
if (pFlac->currentPCMFrame == 0 && pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
return DRFLAC_FALSE;
}
} else {
isMidFrame = DRFLAC_TRUE;
}
} else {
/* Seeking backwards. Need to seek from the start of the file. */
runningPCMFrameCount = 0;
/* Move back to the start. */
if (!drflac__seek_to_first_frame(pFlac)) {
return DRFLAC_FALSE;
}
/* Decode the first frame in preparation for sample-exact seeking below. */
if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
return DRFLAC_FALSE;
}
}
/*
We need to as quickly as possible find the frame that contains the target sample. To do this, we iterate over each frame and inspect its
header. If based on the header we can determine that the frame contains the sample, we do a full decode of that frame.
*/
for (;;) {
drflac_uint64 pcmFrameCountInThisFLACFrame;
drflac_uint64 firstPCMFrameInFLACFrame = 0;
drflac_uint64 lastPCMFrameInFLACFrame = 0;
drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame);
pcmFrameCountInThisFLACFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1;
if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFLACFrame)) {
/*
The sample should be in this frame. We need to fully decode it, however if it's an invalid frame (a CRC mismatch), we need to pretend
it never existed and keep iterating.
*/
drflac_uint64 pcmFramesToDecode = pcmFrameIndex - runningPCMFrameCount;
if (!isMidFrame) {
drflac_result result = drflac__decode_flac_frame(pFlac);
if (result == DRFLAC_SUCCESS) {
/* The frame is valid. We just need to skip over some samples to ensure it's sample-exact. */
return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; /* <-- If this fails, something bad has happened (it should never fail). */
} else {
if (result == DRFLAC_CRC_MISMATCH) {
goto next_iteration; /* CRC mismatch. Pretend this frame never existed. */
} else {
return DRFLAC_FALSE;
}
}
} else {
/* We started seeking mid-frame which means we need to skip the frame decoding part. */
return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode;
}
} else {
/*
It's not in this frame. We need to seek past the frame, but check if there was a CRC mismatch. If so, we pretend this
frame never existed and leave the running sample count untouched.
*/
if (!isMidFrame) {
drflac_result result = drflac__seek_to_next_flac_frame(pFlac);
if (result == DRFLAC_SUCCESS) {
runningPCMFrameCount += pcmFrameCountInThisFLACFrame;
} else {
if (result == DRFLAC_CRC_MISMATCH) {
goto next_iteration; /* CRC mismatch. Pretend this frame never existed. */
} else {
return DRFLAC_FALSE;
}
}
} else {
/*
We started seeking mid-frame which means we need to seek by reading to the end of the frame instead of with
drflac__seek_to_next_flac_frame() which only works if the decoder is sitting on the byte just after the frame header.
*/
runningPCMFrameCount += pFlac->currentFLACFrame.pcmFramesRemaining;
pFlac->currentFLACFrame.pcmFramesRemaining = 0;
isMidFrame = DRFLAC_FALSE;
}
/* If we are seeking to the end of the file and we've just hit it, we're done. */
if (pcmFrameIndex == pFlac->totalPCMFrameCount && runningPCMFrameCount == pFlac->totalPCMFrameCount) {
return DRFLAC_TRUE;
}
}
next_iteration:
/* Grab the next frame in preparation for the next iteration. */
if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
return DRFLAC_FALSE;
}
}
}
#if !defined(DR_FLAC_NO_CRC)
/*
We use an average compression ratio to determine our approximate start location. FLAC files are generally about 50%-70% the size of their
uncompressed counterparts so we'll use this as a basis. I'm going to split the middle and use a factor of 0.6 to determine the starting
location.
*/
#define DRFLAC_BINARY_SEARCH_APPROX_COMPRESSION_RATIO 0.6f
static drflac_bool32 drflac__seek_to_approximate_flac_frame_to_byte(drflac* pFlac, drflac_uint64 targetByte, drflac_uint64 rangeLo, drflac_uint64 rangeHi, drflac_uint64* pLastSuccessfulSeekOffset)
{
DRFLAC_ASSERT(pFlac != NULL);
DRFLAC_ASSERT(pLastSuccessfulSeekOffset != NULL);
DRFLAC_ASSERT(targetByte >= rangeLo);
DRFLAC_ASSERT(targetByte <= rangeHi);
*pLastSuccessfulSeekOffset = pFlac->firstFLACFramePosInBytes;
for (;;) {
/* after rangeLo == rangeHi == targetByte fails, we need to break out */
drflac_uint64 lastTargetByte = targetByte;
/* When seeking to a byte, failure probably means we've attempted to seek beyond the end of the stream. To counter this we just halve it each attempt. */
if (!drflac__seek_to_byte(&pFlac->bs, targetByte)) {
/* If we couldn't even seek to the first byte in the stream we have a problem. Just abandon the whole thing. */
if (targetByte == 0) {
drflac__seek_to_first_frame(pFlac); /* Try to recover. */
return DRFLAC_FALSE;
}
/* Halve the byte location and continue. */
targetByte = rangeLo + ((rangeHi - rangeLo)/2);
rangeHi = targetByte;
} else {
/* Getting here should mean that we have seeked to an appropriate byte. */
/* Clear the details of the FLAC frame so we don't misreport data. */
DRFLAC_ZERO_MEMORY(&pFlac->currentFLACFrame, sizeof(pFlac->currentFLACFrame));
/*
Now seek to the next FLAC frame. We need to decode the entire frame (not just the header) because it's possible for the header to incorrectly pass the
CRC check and return bad data. We need to decode the entire frame to be more certain. Although this seems unlikely, this has happened to me in testing
so it needs to stay this way for now.
*/
#if 1
if (!drflac__read_and_decode_next_flac_frame(pFlac)) {
/* Halve the byte location and continue. */
targetByte = rangeLo + ((rangeHi - rangeLo)/2);
rangeHi = targetByte;
} else {
break;
}
#else
if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
/* Halve the byte location and continue. */
targetByte = rangeLo + ((rangeHi - rangeLo)/2);
rangeHi = targetByte;
} else {
break;
}
#endif
}
// we already tried this byte and there are no more to try, break out
if(targetByte == lastTargetByte)
{
return DRFLAC_FALSE;
}
}
/* The current PCM frame needs to be updated based on the frame we just seeked to. */
drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &pFlac->currentPCMFrame, NULL);
DRFLAC_ASSERT(targetByte <= rangeHi);
*pLastSuccessfulSeekOffset = targetByte;
return DRFLAC_TRUE;
}
static drflac_bool32 drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(drflac* pFlac, drflac_uint64 offset)
{
/* This section of code would be used if we were only decoding the FLAC frame header when calling drflac__seek_to_approximate_flac_frame_to_byte(). */
#if 0
if (drflac__decode_flac_frame(pFlac) != DRFLAC_SUCCESS) {
/* We failed to decode this frame which may be due to it being corrupt. We'll just use the next valid FLAC frame. */
if (drflac__read_and_decode_next_flac_frame(pFlac) == DRFLAC_FALSE) {
return DRFLAC_FALSE;
}
}
#endif
return drflac__seek_forward_by_pcm_frames(pFlac, offset) == offset;
}
static drflac_bool32 drflac__seek_to_pcm_frame__binary_search_internal(drflac* pFlac, drflac_uint64 pcmFrameIndex, drflac_uint64 byteRangeLo, drflac_uint64 byteRangeHi)
{
/* This assumes pFlac->currentPCMFrame is sitting on byteRangeLo upon entry. */
drflac_uint64 targetByte;
drflac_uint64 pcmRangeLo = pFlac->totalPCMFrameCount;
drflac_uint64 pcmRangeHi = 0;
drflac_uint64 lastSuccessfulSeekOffset = (drflac_uint64)-1;
drflac_uint64 closestSeekOffsetBeforeTargetPCMFrame = byteRangeLo;
drflac_uint32 seekForwardThreshold = (pFlac->maxBlockSizeInPCMFrames != 0) ? pFlac->maxBlockSizeInPCMFrames*2 : 4096;
targetByte = byteRangeLo + (drflac_uint64)(((drflac_int64)((pcmFrameIndex - pFlac->currentPCMFrame) * pFlac->channels * pFlac->bitsPerSample)/8.0f) * DRFLAC_BINARY_SEARCH_APPROX_COMPRESSION_RATIO);
if (targetByte > byteRangeHi) {
targetByte = byteRangeHi;
}
for (;;) {
if (drflac__seek_to_approximate_flac_frame_to_byte(pFlac, targetByte, byteRangeLo, byteRangeHi, &lastSuccessfulSeekOffset)) {
/* We found a FLAC frame. We need to check if it contains the sample we're looking for. */
drflac_uint64 newPCMRangeLo;
drflac_uint64 newPCMRangeHi;
drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &newPCMRangeLo, &newPCMRangeHi);
/* If we selected the same frame, it means we should be pretty close. Just decode the rest. */
if (pcmRangeLo == newPCMRangeLo) {
if (!drflac__seek_to_approximate_flac_frame_to_byte(pFlac, closestSeekOffsetBeforeTargetPCMFrame, closestSeekOffsetBeforeTargetPCMFrame, byteRangeHi, &lastSuccessfulSeekOffset)) {
break; /* Failed to seek to closest frame. */
}
if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame)) {
return DRFLAC_TRUE;
} else {
break; /* Failed to seek forward. */
}
}
pcmRangeLo = newPCMRangeLo;
pcmRangeHi = newPCMRangeHi;
if (pcmRangeLo <= pcmFrameIndex && pcmRangeHi >= pcmFrameIndex) {
/* The target PCM frame is in this FLAC frame. */
if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame) ) {
return DRFLAC_TRUE;
} else {
break; /* Failed to seek to FLAC frame. */
}
} else {
const float approxCompressionRatio = (drflac_int64)(lastSuccessfulSeekOffset - pFlac->firstFLACFramePosInBytes) / ((drflac_int64)(pcmRangeLo * pFlac->channels * pFlac->bitsPerSample)/8.0f);
if (pcmRangeLo > pcmFrameIndex) {
/* We seeked too far forward. We need to move our target byte backward and try again. */
byteRangeHi = lastSuccessfulSeekOffset;
if (byteRangeLo > byteRangeHi) {
byteRangeLo = byteRangeHi;
}
targetByte = byteRangeLo + ((byteRangeHi - byteRangeLo) / 2);
if (targetByte < byteRangeLo) {
targetByte = byteRangeLo;
}
} else /*if (pcmRangeHi < pcmFrameIndex)*/ {
/* We didn't seek far enough. We need to move our target byte forward and try again. */
/* If we're close enough we can just seek forward. */
if ((pcmFrameIndex - pcmRangeLo) < seekForwardThreshold) {
if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame)) {
return DRFLAC_TRUE;
} else {
break; /* Failed to seek to FLAC frame. */
}
} else {
byteRangeLo = lastSuccessfulSeekOffset;
if (byteRangeHi < byteRangeLo) {
byteRangeHi = byteRangeLo;
}
targetByte = lastSuccessfulSeekOffset + (drflac_uint64)(((drflac_int64)((pcmFrameIndex-pcmRangeLo) * pFlac->channels * pFlac->bitsPerSample)/8.0f) * approxCompressionRatio);
if (targetByte > byteRangeHi) {
targetByte = byteRangeHi;
}
if (closestSeekOffsetBeforeTargetPCMFrame < lastSuccessfulSeekOffset) {
closestSeekOffsetBeforeTargetPCMFrame = lastSuccessfulSeekOffset;
}
}
}
}
} else {
/* Getting here is really bad. We just recover as best we can, but moving to the first frame in the stream, and then abort. */
break;
}
}
drflac__seek_to_first_frame(pFlac); /* <-- Try to recover. */
return DRFLAC_FALSE;
}
static drflac_bool32 drflac__seek_to_pcm_frame__binary_search(drflac* pFlac, drflac_uint64 pcmFrameIndex)
{
drflac_uint64 byteRangeLo;
drflac_uint64 byteRangeHi;
drflac_uint32 seekForwardThreshold = (pFlac->maxBlockSizeInPCMFrames != 0) ? pFlac->maxBlockSizeInPCMFrames*2 : 4096;
/* Our algorithm currently assumes the FLAC stream is currently sitting at the start. */
if (drflac__seek_to_first_frame(pFlac) == DRFLAC_FALSE) {
return DRFLAC_FALSE;
}
/* If we're close enough to the start, just move to the start and seek forward. */
if (pcmFrameIndex < seekForwardThreshold) {
return drflac__seek_forward_by_pcm_frames(pFlac, pcmFrameIndex) == pcmFrameIndex;
}
/*
Our starting byte range is the byte position of the first FLAC frame and the approximate end of the file as if it were completely uncompressed. This ensures
the entire file is included, even though most of the time it'll exceed the end of the actual stream. This is OK as the frame searching logic will handle it.
*/
byteRangeLo = pFlac->firstFLACFramePosInBytes;
byteRangeHi = pFlac->firstFLACFramePosInBytes + (drflac_uint64)((drflac_int64)(pFlac->totalPCMFrameCount * pFlac->channels * pFlac->bitsPerSample)/8.0f);
return drflac__seek_to_pcm_frame__binary_search_internal(pFlac, pcmFrameIndex, byteRangeLo, byteRangeHi);
}
#endif /* !DR_FLAC_NO_CRC */
static drflac_bool32 drflac__seek_to_pcm_frame__seek_table(drflac* pFlac, drflac_uint64 pcmFrameIndex)
{
drflac_uint32 iClosestSeekpoint = 0;
drflac_bool32 isMidFrame = DRFLAC_FALSE;
drflac_uint64 runningPCMFrameCount;
drflac_uint32 iSeekpoint;
DRFLAC_ASSERT(pFlac != NULL);
if (pFlac->pSeekpoints == NULL || pFlac->seekpointCount == 0) {
return DRFLAC_FALSE;
}
for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) {
if (pFlac->pSeekpoints[iSeekpoint].firstPCMFrame >= pcmFrameIndex) {
break;
}
iClosestSeekpoint = iSeekpoint;
}
/* There's been cases where the seek table contains only zeros. We need to do some basic validation on the closest seekpoint. */
if (pFlac->pSeekpoints[iClosestSeekpoint].pcmFrameCount == 0 || pFlac->pSeekpoints[iClosestSeekpoint].pcmFrameCount > pFlac->maxBlockSizeInPCMFrames) {
return DRFLAC_FALSE;
}
if (pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame > pFlac->totalPCMFrameCount && pFlac->totalPCMFrameCount > 0) {
return DRFLAC_FALSE;
}
#if !defined(DR_FLAC_NO_CRC)
/* At this point we should know the closest seek point. We can use a binary search for this. We need to know the total sample count for this. */
if (pFlac->totalPCMFrameCount > 0) {
drflac_uint64 byteRangeLo;
drflac_uint64 byteRangeHi;
byteRangeHi = pFlac->firstFLACFramePosInBytes + (drflac_uint64)((drflac_int64)(pFlac->totalPCMFrameCount * pFlac->channels * pFlac->bitsPerSample)/8.0f);
byteRangeLo = pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset;
/*
If our closest seek point is not the last one, we only need to search between it and the next one. The section below calculates an appropriate starting
value for byteRangeHi which will clamp it appropriately.
Note that the next seekpoint must have an offset greater than the closest seekpoint because otherwise our binary search algorithm will break down. There
have been cases where a seektable consists of seek points where every byte offset is set to 0 which causes problems. If this happens we need to abort.
*/
if (iClosestSeekpoint < pFlac->seekpointCount-1) {
drflac_uint32 iNextSeekpoint = iClosestSeekpoint + 1;
/* Basic validation on the seekpoints to ensure they're usable. */
if (pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset >= pFlac->pSeekpoints[iNextSeekpoint].flacFrameOffset || pFlac->pSeekpoints[iNextSeekpoint].pcmFrameCount == 0) {
return DRFLAC_FALSE; /* The next seekpoint doesn't look right. The seek table cannot be trusted from here. Abort. */
}
if (pFlac->pSeekpoints[iNextSeekpoint].firstPCMFrame != (((drflac_uint64)0xFFFFFFFF << 32) | 0xFFFFFFFF)) { /* Make sure it's not a placeholder seekpoint. */
byteRangeHi = pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iNextSeekpoint].flacFrameOffset - 1; /* byteRangeHi must be zero based. */
}
}
if (drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset)) {
if (drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &pFlac->currentPCMFrame, NULL);
if (drflac__seek_to_pcm_frame__binary_search_internal(pFlac, pcmFrameIndex, byteRangeLo, byteRangeHi)) {
return DRFLAC_TRUE;
}
}
}
}
#endif /* !DR_FLAC_NO_CRC */
/* Getting here means we need to use a slower algorithm because the binary search method failed or cannot be used. */
/*
If we are seeking forward and the closest seekpoint is _before_ the current sample, we just seek forward from where we are. Otherwise we start seeking
from the seekpoint's first sample.
*/
if (pcmFrameIndex >= pFlac->currentPCMFrame && pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame <= pFlac->currentPCMFrame) {
/* Optimized case. Just seek forward from where we are. */
runningPCMFrameCount = pFlac->currentPCMFrame;
/* The frame header for the first frame may not yet have been read. We need to do that if necessary. */
if (pFlac->currentPCMFrame == 0 && pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
return DRFLAC_FALSE;
}
} else {
isMidFrame = DRFLAC_TRUE;
}
} else {
/* Slower case. Seek to the start of the seekpoint and then seek forward from there. */
runningPCMFrameCount = pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame;
if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset)) {
return DRFLAC_FALSE;
}
/* Grab the frame the seekpoint is sitting on in preparation for the sample-exact seeking below. */
if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
return DRFLAC_FALSE;
}
}
for (;;) {
drflac_uint64 pcmFrameCountInThisFLACFrame;
drflac_uint64 firstPCMFrameInFLACFrame = 0;
drflac_uint64 lastPCMFrameInFLACFrame = 0;
drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame);
pcmFrameCountInThisFLACFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1;
if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFLACFrame)) {
/*
The sample should be in this frame. We need to fully decode it, but if it's an invalid frame (a CRC mismatch) we need to pretend
it never existed and keep iterating.
*/
drflac_uint64 pcmFramesToDecode = pcmFrameIndex - runningPCMFrameCount;
if (!isMidFrame) {
drflac_result result = drflac__decode_flac_frame(pFlac);
if (result == DRFLAC_SUCCESS) {
/* The frame is valid. We just need to skip over some samples to ensure it's sample-exact. */
return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; /* <-- If this fails, something bad has happened (it should never fail). */
} else {
if (result == DRFLAC_CRC_MISMATCH) {
goto next_iteration; /* CRC mismatch. Pretend this frame never existed. */
} else {
return DRFLAC_FALSE;
}
}
} else {
/* We started seeking mid-frame which means we need to skip the frame decoding part. */
return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode;
}
} else {
/*
It's not in this frame. We need to seek past the frame, but check if there was a CRC mismatch. If so, we pretend this
frame never existed and leave the running sample count untouched.
*/
if (!isMidFrame) {
drflac_result result = drflac__seek_to_next_flac_frame(pFlac);
if (result == DRFLAC_SUCCESS) {
runningPCMFrameCount += pcmFrameCountInThisFLACFrame;
} else {
if (result == DRFLAC_CRC_MISMATCH) {
goto next_iteration; /* CRC mismatch. Pretend this frame never existed. */
} else {
return DRFLAC_FALSE;
}
}
} else {
/*
We started seeking mid-frame which means we need to seek by reading to the end of the frame instead of with
drflac__seek_to_next_flac_frame() which only works if the decoder is sitting on the byte just after the frame header.
*/
runningPCMFrameCount += pFlac->currentFLACFrame.pcmFramesRemaining;
pFlac->currentFLACFrame.pcmFramesRemaining = 0;
isMidFrame = DRFLAC_FALSE;
}
/* If we are seeking to the end of the file and we've just hit it, we're done. */
if (pcmFrameIndex == pFlac->totalPCMFrameCount && runningPCMFrameCount == pFlac->totalPCMFrameCount) {
return DRFLAC_TRUE;
}
}
next_iteration:
/* Grab the next frame in preparation for the next iteration. */
if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
return DRFLAC_FALSE;
}
}
}
#ifndef DR_FLAC_NO_OGG
typedef struct
{
drflac_uint8 capturePattern[4]; /* Should be "OggS" */
drflac_uint8 structureVersion; /* Always 0. */
drflac_uint8 headerType;
drflac_uint64 granulePosition;
drflac_uint32 serialNumber;
drflac_uint32 sequenceNumber;
drflac_uint32 checksum;
drflac_uint8 segmentCount;
drflac_uint8 segmentTable[255];
} drflac_ogg_page_header;
#endif
typedef struct
{
drflac_read_proc onRead;
drflac_seek_proc onSeek;
drflac_meta_proc onMeta;
drflac_container container;
void* pUserData;
void* pUserDataMD;
drflac_uint32 sampleRate;
drflac_uint8 channels;
drflac_uint8 bitsPerSample;
drflac_uint64 totalPCMFrameCount;
drflac_uint16 maxBlockSizeInPCMFrames;
drflac_uint64 runningFilePos;
drflac_bool32 hasStreamInfoBlock;
drflac_bool32 hasMetadataBlocks;
drflac_bs bs; /* <-- A bit streamer is required for loading data during initialization. */
drflac_frame_header firstFrameHeader; /* <-- The header of the first frame that was read during relaxed initalization. Only set if there is no STREAMINFO block. */
#ifndef DR_FLAC_NO_OGG
drflac_uint32 oggSerial;
drflac_uint64 oggFirstBytePos;
drflac_ogg_page_header oggBosHeader;
#endif
} drflac_init_info;
static DRFLAC_INLINE void drflac__decode_block_header(drflac_uint32 blockHeader, drflac_uint8* isLastBlock, drflac_uint8* blockType, drflac_uint32* blockSize)
{
blockHeader = drflac__be2host_32(blockHeader);
*isLastBlock = (drflac_uint8)((blockHeader & 0x80000000UL) >> 31);
*blockType = (drflac_uint8)((blockHeader & 0x7F000000UL) >> 24);
*blockSize = (blockHeader & 0x00FFFFFFUL);
}
static DRFLAC_INLINE drflac_bool32 drflac__read_and_decode_block_header(drflac_read_proc onRead, void* pUserData, drflac_uint8* isLastBlock, drflac_uint8* blockType, drflac_uint32* blockSize)
{
drflac_uint32 blockHeader;
*blockSize = 0;
if (onRead(pUserData, &blockHeader, 4) != 4) {
return DRFLAC_FALSE;
}
drflac__decode_block_header(blockHeader, isLastBlock, blockType, blockSize);
return DRFLAC_TRUE;
}
static drflac_bool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, drflac_streaminfo* pStreamInfo)
{
drflac_uint32 blockSizes;
drflac_uint64 frameSizes = 0;
drflac_uint64 importantProps;
drflac_uint8 md5[16];
/* min/max block size. */
if (onRead(pUserData, &blockSizes, 4) != 4) {
return DRFLAC_FALSE;
}
/* min/max frame size. */
if (onRead(pUserData, &frameSizes, 6) != 6) {
return DRFLAC_FALSE;
}
/* Sample rate, channels, bits per sample and total sample count. */
if (onRead(pUserData, &importantProps, 8) != 8) {
return DRFLAC_FALSE;
}
/* MD5 */
if (onRead(pUserData, md5, sizeof(md5)) != sizeof(md5)) {
return DRFLAC_FALSE;
}
blockSizes = drflac__be2host_32(blockSizes);
frameSizes = drflac__be2host_64(frameSizes);
importantProps = drflac__be2host_64(importantProps);
pStreamInfo->minBlockSizeInPCMFrames = (drflac_uint16)((blockSizes & 0xFFFF0000) >> 16);
pStreamInfo->maxBlockSizeInPCMFrames = (drflac_uint16) (blockSizes & 0x0000FFFF);
pStreamInfo->minFrameSizeInPCMFrames = (drflac_uint32)((frameSizes & (((drflac_uint64)0x00FFFFFF << 16) << 24)) >> 40);
pStreamInfo->maxFrameSizeInPCMFrames = (drflac_uint32)((frameSizes & (((drflac_uint64)0x00FFFFFF << 16) << 0)) >> 16);
pStreamInfo->sampleRate = (drflac_uint32)((importantProps & (((drflac_uint64)0x000FFFFF << 16) << 28)) >> 44);
pStreamInfo->channels = (drflac_uint8 )((importantProps & (((drflac_uint64)0x0000000E << 16) << 24)) >> 41) + 1;
pStreamInfo->bitsPerSample = (drflac_uint8 )((importantProps & (((drflac_uint64)0x0000001F << 16) << 20)) >> 36) + 1;
pStreamInfo->totalPCMFrameCount = ((importantProps & ((((drflac_uint64)0x0000000F << 16) << 16) | 0xFFFFFFFF)));
DRFLAC_COPY_MEMORY(pStreamInfo->md5, md5, sizeof(md5));
return DRFLAC_TRUE;
}
static void* drflac__malloc_default(size_t sz, void* pUserData)
{
(void)pUserData;
return DRFLAC_MALLOC(sz);
}
static void* drflac__realloc_default(void* p, size_t sz, void* pUserData)
{
(void)pUserData;
return DRFLAC_REALLOC(p, sz);
}
static void drflac__free_default(void* p, void* pUserData)
{
(void)pUserData;
DRFLAC_FREE(p);
}
static void* drflac__malloc_from_callbacks(size_t sz, const drflac_allocation_callbacks* pAllocationCallbacks)
{
if (pAllocationCallbacks == NULL) {
return NULL;
}
if (pAllocationCallbacks->onMalloc != NULL) {
return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData);
}
/* Try using realloc(). */
if (pAllocationCallbacks->onRealloc != NULL) {
return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData);
}
return NULL;
}
static void* drflac__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drflac_allocation_callbacks* pAllocationCallbacks)
{
if (pAllocationCallbacks == NULL) {
return NULL;
}
if (pAllocationCallbacks->onRealloc != NULL) {
return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData);
}
/* Try emulating realloc() in terms of malloc()/free(). */
if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) {
void* p2;
share/public_html/static/music_inc/src/dr_flac.h view on Meta::CPAN
return DRFLAC_FALSE;
}
if (onRead(pUserData, pRawData, blockSize) != blockSize) {
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
return DRFLAC_FALSE;
}
metadata.pRawData = pRawData;
metadata.rawDataSize = blockSize;
onMeta(pUserDataMD, &metadata);
drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
}
} break;
}
/* If we're not handling metadata, just skip over the block. If we are, it will have been handled earlier in the switch statement above. */
if (onMeta == NULL && blockSize > 0) {
if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) {
isLastBlock = DRFLAC_TRUE;
}
}
runningFilePos += blockSize;
if (isLastBlock) {
break;
}
}
*pSeektablePos = seektablePos;
*pSeektableSize = seektableSize;
*pFirstFramePos = runningFilePos;
return DRFLAC_TRUE;
}
static drflac_bool32 drflac__init_private__native(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_bool32 relaxed)
{
/* Pre Condition: The bit stream should be sitting just past the 4-byte id header. */
drflac_uint8 isLastBlock;
drflac_uint8 blockType;
drflac_uint32 blockSize;
(void)onSeek;
pInit->container = drflac_container_native;
/* The first metadata block should be the STREAMINFO block. */
if (!drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize)) {
return DRFLAC_FALSE;
}
if (blockType != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) {
if (!relaxed) {
/* We're opening in strict mode and the first block is not the STREAMINFO block. Error. */
return DRFLAC_FALSE;
} else {
/*
Relaxed mode. To open from here we need to just find the first frame and set the sample rate, etc. to whatever is defined
for that frame.
*/
pInit->hasStreamInfoBlock = DRFLAC_FALSE;
pInit->hasMetadataBlocks = DRFLAC_FALSE;
if (!drflac__read_next_flac_frame_header(&pInit->bs, 0, &pInit->firstFrameHeader)) {
return DRFLAC_FALSE; /* Couldn't find a frame. */
}
if (pInit->firstFrameHeader.bitsPerSample == 0) {
return DRFLAC_FALSE; /* Failed to initialize because the first frame depends on the STREAMINFO block, which does not exist. */
}
pInit->sampleRate = pInit->firstFrameHeader.sampleRate;
pInit->channels = drflac__get_channel_count_from_channel_assignment(pInit->firstFrameHeader.channelAssignment);
pInit->bitsPerSample = pInit->firstFrameHeader.bitsPerSample;
pInit->maxBlockSizeInPCMFrames = 65535; /* <-- See notes here: https://xiph.org/flac/format.html#metadata_block_streaminfo */
return DRFLAC_TRUE;
}
} else {
drflac_streaminfo streaminfo;
if (!drflac__read_streaminfo(onRead, pUserData, &streaminfo)) {
return DRFLAC_FALSE;
}
pInit->hasStreamInfoBlock = DRFLAC_TRUE;
pInit->sampleRate = streaminfo.sampleRate;
pInit->channels = streaminfo.channels;
pInit->bitsPerSample = streaminfo.bitsPerSample;
pInit->totalPCMFrameCount = streaminfo.totalPCMFrameCount;
pInit->maxBlockSizeInPCMFrames = streaminfo.maxBlockSizeInPCMFrames; /* Don't care about the min block size - only the max (used for determining the size of the memory allocation). */
pInit->hasMetadataBlocks = !isLastBlock;
if (onMeta) {
drflac_metadata metadata;
metadata.type = DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO;
metadata.pRawData = NULL;
metadata.rawDataSize = 0;
metadata.data.streaminfo = streaminfo;
onMeta(pUserDataMD, &metadata);
}
return DRFLAC_TRUE;
}
}
#ifndef DR_FLAC_NO_OGG
#define DRFLAC_OGG_MAX_PAGE_SIZE 65307
#define DRFLAC_OGG_CAPTURE_PATTERN_CRC32 1605413199 /* CRC-32 of "OggS". */
typedef enum
{
drflac_ogg_recover_on_crc_mismatch,
drflac_ogg_fail_on_crc_mismatch
} drflac_ogg_crc_mismatch_recovery;
#ifndef DR_FLAC_NO_CRC
static drflac_uint32 drflac__crc32_table[] = {
0x00000000L, 0x04C11DB7L, 0x09823B6EL, 0x0D4326D9L,
0x130476DCL, 0x17C56B6BL, 0x1A864DB2L, 0x1E475005L,
0x2608EDB8L, 0x22C9F00FL, 0x2F8AD6D6L, 0x2B4BCB61L,
0x350C9B64L, 0x31CD86D3L, 0x3C8EA00AL, 0x384FBDBDL,
0x4C11DB70L, 0x48D0C6C7L, 0x4593E01EL, 0x4152FDA9L,
0x5F15ADACL, 0x5BD4B01BL, 0x569796C2L, 0x52568B75L,
0x6A1936C8L, 0x6ED82B7FL, 0x639B0DA6L, 0x675A1011L,
0x791D4014L, 0x7DDC5DA3L, 0x709F7B7AL, 0x745E66CDL,
0x9823B6E0L, 0x9CE2AB57L, 0x91A18D8EL, 0x95609039L,
0x8B27C03CL, 0x8FE6DD8BL, 0x82A5FB52L, 0x8664E6E5L,
0xBE2B5B58L, 0xBAEA46EFL, 0xB7A96036L, 0xB3687D81L,
0xAD2F2D84L, 0xA9EE3033L, 0xA4AD16EAL, 0xA06C0B5DL,
0xD4326D90L, 0xD0F37027L, 0xDDB056FEL, 0xD9714B49L,
share/public_html/static/music_inc/src/dr_flac.h view on Meta::CPAN
} else {
iSeg += 1;
iByte += segmentSize;
}
}
*pBytesRemainingInSeg = oggbs->currentPageHeader.segmentTable[iSeg] - (drflac_uint8)(bytesConsumedInPage - iByte);
return iSeg;
}
static drflac_bool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs)
{
/* The current packet ends when we get to the segment with a lacing value of < 255 which is not at the end of a page. */
for (;;) {
drflac_bool32 atEndOfPage = DRFLAC_FALSE;
drflac_uint8 bytesRemainingInSeg;
drflac_uint8 iFirstSeg = drflac_oggbs__get_current_segment_index(oggbs, &bytesRemainingInSeg);
drflac_uint32 bytesToEndOfPacketOrPage = bytesRemainingInSeg;
for (drflac_uint8 iSeg = iFirstSeg; iSeg < oggbs->currentPageHeader.segmentCount; ++iSeg) {
drflac_uint8 segmentSize = oggbs->currentPageHeader.segmentTable[iSeg];
if (segmentSize < 255) {
if (iSeg == oggbs->currentPageHeader.segmentCount-1) {
atEndOfPage = DRFLAC_TRUE;
}
break;
}
bytesToEndOfPacketOrPage += segmentSize;
}
/*
At this point we will have found either the packet or the end of the page. If were at the end of the page we'll
want to load the next page and keep searching for the end of the packet.
*/
drflac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, drflac_seek_origin_current);
oggbs->bytesRemainingInPage -= bytesToEndOfPacketOrPage;
if (atEndOfPage) {
/*
We're potentially at the next packet, but we need to check the next page first to be sure because the packet may
straddle pages.
*/
if (!drflac_oggbs__goto_next_page(oggbs)) {
return DRFLAC_FALSE;
}
/* If it's a fresh packet it most likely means we're at the next packet. */
if ((oggbs->currentPageHeader.headerType & 0x01) == 0) {
return DRFLAC_TRUE;
}
} else {
/* We're at the next packet. */
return DRFLAC_TRUE;
}
}
}
static drflac_bool32 drflac_oggbs__seek_to_next_frame(drflac_oggbs* oggbs)
{
/* The bitstream should be sitting on the first byte just after the header of the frame. */
/* What we're actually doing here is seeking to the start of the next packet. */
return drflac_oggbs__seek_to_next_packet(oggbs);
}
#endif
static size_t drflac__on_read_ogg(void* pUserData, void* bufferOut, size_t bytesToRead)
{
drflac_oggbs* oggbs = (drflac_oggbs*)pUserData;
drflac_uint8* pRunningBufferOut = (drflac_uint8*)bufferOut;
size_t bytesRead = 0;
DRFLAC_ASSERT(oggbs != NULL);
DRFLAC_ASSERT(pRunningBufferOut != NULL);
/* Reading is done page-by-page. If we've run out of bytes in the page we need to move to the next one. */
while (bytesRead < bytesToRead) {
size_t bytesRemainingToRead = bytesToRead - bytesRead;
if (oggbs->bytesRemainingInPage >= bytesRemainingToRead) {
DRFLAC_COPY_MEMORY(pRunningBufferOut, oggbs->pageData + (oggbs->pageDataSize - oggbs->bytesRemainingInPage), bytesRemainingToRead);
bytesRead += bytesRemainingToRead;
oggbs->bytesRemainingInPage -= (drflac_uint32)bytesRemainingToRead;
break;
}
/* If we get here it means some of the requested data is contained in the next pages. */
if (oggbs->bytesRemainingInPage > 0) {
DRFLAC_COPY_MEMORY(pRunningBufferOut, oggbs->pageData + (oggbs->pageDataSize - oggbs->bytesRemainingInPage), oggbs->bytesRemainingInPage);
bytesRead += oggbs->bytesRemainingInPage;
pRunningBufferOut += oggbs->bytesRemainingInPage;
oggbs->bytesRemainingInPage = 0;
}
DRFLAC_ASSERT(bytesRemainingToRead > 0);
if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) {
break; /* Failed to go to the next page. Might have simply hit the end of the stream. */
}
}
return bytesRead;
}
static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_seek_origin origin)
{
drflac_oggbs* oggbs = (drflac_oggbs*)pUserData;
int bytesSeeked = 0;
DRFLAC_ASSERT(oggbs != NULL);
DRFLAC_ASSERT(offset >= 0); /* <-- Never seek backwards. */
/* Seeking is always forward which makes things a lot simpler. */
if (origin == drflac_seek_origin_start) {
if (!drflac_oggbs__seek_physical(oggbs, (int)oggbs->firstBytePos, drflac_seek_origin_start)) {
return DRFLAC_FALSE;
}
if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_fail_on_crc_mismatch)) {
return DRFLAC_FALSE;
}
return drflac__on_seek_ogg(pUserData, offset, drflac_seek_origin_current);
}
DRFLAC_ASSERT(origin == drflac_seek_origin_current);
while (bytesSeeked < offset) {
int bytesRemainingToSeek = offset - bytesSeeked;
DRFLAC_ASSERT(bytesRemainingToSeek >= 0);
if (oggbs->bytesRemainingInPage >= (size_t)bytesRemainingToSeek) {
bytesSeeked += bytesRemainingToSeek;
(void)bytesSeeked; /* <-- Silence a dead store warning emitted by Clang Static Analyzer. */
oggbs->bytesRemainingInPage -= bytesRemainingToSeek;
break;
}
/* If we get here it means some of the requested data is contained in the next pages. */
if (oggbs->bytesRemainingInPage > 0) {
bytesSeeked += (int)oggbs->bytesRemainingInPage;
oggbs->bytesRemainingInPage = 0;
}
DRFLAC_ASSERT(bytesRemainingToSeek > 0);
if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_fail_on_crc_mismatch)) {
/* Failed to go to the next page. We either hit the end of the stream or had a CRC mismatch. */
return DRFLAC_FALSE;
}
}
return DRFLAC_TRUE;
}
static drflac_bool32 drflac_ogg__seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex)
{
drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs;
drflac_uint64 originalBytePos;
drflac_uint64 runningGranulePosition;
drflac_uint64 runningFrameBytePos;
drflac_uint64 runningPCMFrameCount;
DRFLAC_ASSERT(oggbs != NULL);
originalBytePos = oggbs->currentBytePos; /* For recovery. Points to the OggS identifier. */
/* First seek to the first frame. */
if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes)) {
return DRFLAC_FALSE;
}
oggbs->bytesRemainingInPage = 0;
runningGranulePosition = 0;
for (;;) {
if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) {
drflac_oggbs__seek_physical(oggbs, originalBytePos, drflac_seek_origin_start);
return DRFLAC_FALSE; /* Never did find that sample... */
}
runningFrameBytePos = oggbs->currentBytePos - drflac_ogg__get_page_header_size(&oggbs->currentPageHeader) - oggbs->pageDataSize;
if (oggbs->currentPageHeader.granulePosition >= pcmFrameIndex) {
break; /* The sample is somewhere in the previous page. */
}
/*
At this point we know the sample is not in the previous page. It could possibly be in this page. For simplicity we
disregard any pages that do not begin a fresh packet.
*/
if ((oggbs->currentPageHeader.headerType & 0x01) == 0) { /* <-- Is it a fresh page? */
if (oggbs->currentPageHeader.segmentTable[0] >= 2) {
drflac_uint8 firstBytesInPage[2];
firstBytesInPage[0] = oggbs->pageData[0];
firstBytesInPage[1] = oggbs->pageData[1];
if ((firstBytesInPage[0] == 0xFF) && (firstBytesInPage[1] & 0xFC) == 0xF8) { /* <-- Does the page begin with a frame's sync code? */
runningGranulePosition = oggbs->currentPageHeader.granulePosition;
}
continue;
}
}
}
/*
We found the page that that is closest to the sample, so now we need to find it. The first thing to do is seek to the
start of that page. In the loop above we checked that it was a fresh page which means this page is also the start of
a new frame. This property means that after we've seeked to the page we can immediately start looping over frames until
we find the one containing the target sample.
*/
if (!drflac_oggbs__seek_physical(oggbs, runningFrameBytePos, drflac_seek_origin_start)) {
return DRFLAC_FALSE;
}
if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) {
return DRFLAC_FALSE;
}
/*
At this point we'll be sitting on the first byte of the frame header of the first frame in the page. We just keep
looping over these frames until we find the one containing the sample we're after.
*/
runningPCMFrameCount = runningGranulePosition;
for (;;) {
/*
There are two ways to find the sample and seek past irrelevant frames:
1) Use the native FLAC decoder.
2) Use Ogg's framing system.
Both of these options have their own pros and cons. Using the native FLAC decoder is slower because it needs to
do a full decode of the frame. Using Ogg's framing system is faster, but more complicated and involves some code
duplication for the decoding of frame headers.
Another thing to consider is that using the Ogg framing system will perform direct seeking of the physical Ogg
bitstream. This is important to consider because it means we cannot read data from the drflac_bs object using the
standard drflac__*() APIs because that will read in extra data for its own internal caching which in turn breaks
the positioning of the read pointer of the physical Ogg bitstream. Therefore, anything that would normally be read
using the native FLAC decoding APIs, such as drflac__read_next_flac_frame_header(), need to be re-implemented so as to
avoid the use of the drflac_bs object.
Considering these issues, I have decided to use the slower native FLAC decoding method for the following reasons:
1) Seeking is already partially accelerated using Ogg's paging system in the code block above.
2) Seeking in an Ogg encapsulated FLAC stream is probably quite uncommon.
3) Simplicity.
*/
drflac_uint64 firstPCMFrameInFLACFrame = 0;
drflac_uint64 lastPCMFrameInFLACFrame = 0;
drflac_uint64 pcmFrameCountInThisFrame;
if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
return DRFLAC_FALSE;
}
drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame);
pcmFrameCountInThisFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1;
/* If we are seeking to the end of the file and we've just hit it, we're done. */
if (pcmFrameIndex == pFlac->totalPCMFrameCount && (runningPCMFrameCount + pcmFrameCountInThisFrame) == pFlac->totalPCMFrameCount) {
drflac_result result = drflac__decode_flac_frame(pFlac);
if (result == DRFLAC_SUCCESS) {
pFlac->currentPCMFrame = pcmFrameIndex;
pFlac->currentFLACFrame.pcmFramesRemaining = 0;
return DRFLAC_TRUE;
} else {
return DRFLAC_FALSE;
}
}
if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFrame)) {
/*
The sample should be in this FLAC frame. We need to fully decode it, however if it's an invalid frame (a CRC mismatch), we need to pretend
it never existed and keep iterating.
*/
drflac_result result = drflac__decode_flac_frame(pFlac);
if (result == DRFLAC_SUCCESS) {
/* The frame is valid. We just need to skip over some samples to ensure it's sample-exact. */
drflac_uint64 pcmFramesToDecode = (size_t)(pcmFrameIndex - runningPCMFrameCount); /* <-- Safe cast because the maximum number of samples in a frame is 65535. */
if (pcmFramesToDecode == 0) {
return DRFLAC_TRUE;
}
pFlac->currentPCMFrame = runningPCMFrameCount;
return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; /* <-- If this fails, something bad has happened (it should never fail). */
} else {
if (result == DRFLAC_CRC_MISMATCH) {
continue; /* CRC mismatch. Pretend this frame never existed. */
} else {
return DRFLAC_FALSE;
}
}
} else {
/*
It's not in this frame. We need to seek past the frame, but check if there was a CRC mismatch. If so, we pretend this
frame never existed and leave the running sample count untouched.
*/
drflac_result result = drflac__seek_to_next_flac_frame(pFlac);
if (result == DRFLAC_SUCCESS) {
runningPCMFrameCount += pcmFrameCountInThisFrame;
} else {
if (result == DRFLAC_CRC_MISMATCH) {
continue; /* CRC mismatch. Pretend this frame never existed. */
} else {
return DRFLAC_FALSE;
}
}
}
}
}
static drflac_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_bool32 relaxed)
{
drflac_ogg_page_header header;
drflac_uint32 crc32 = DRFLAC_OGG_CAPTURE_PATTERN_CRC32;
drflac_uint32 bytesRead = 0;
/* Pre Condition: The bit stream should be sitting just past the 4-byte OggS capture pattern. */
(void)relaxed;
pInit->container = drflac_container_ogg;
pInit->oggFirstBytePos = 0;
/*
We'll get here if the first 4 bytes of the stream were the OggS capture pattern, however it doesn't necessarily mean the
stream includes FLAC encoded audio. To check for this we need to scan the beginning-of-stream page markers and check if
any match the FLAC specification. Important to keep in mind that the stream may be multiplexed.
*/
if (drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) {
return DRFLAC_FALSE;
}
pInit->runningFilePos += bytesRead;
for (;;) {
int pageBodySize;
/* Break if we're past the beginning of stream page. */
if ((header.headerType & 0x02) == 0) {
return DRFLAC_FALSE;
}
/* Check if it's a FLAC header. */
pageBodySize = drflac_ogg__get_page_body_size(&header);
if (pageBodySize == 51) { /* 51 = the lacing value of the FLAC header packet. */
/* It could be a FLAC page... */
drflac_uint32 bytesRemainingInPage = pageBodySize;
drflac_uint8 packetType;
if (onRead(pUserData, &packetType, 1) != 1) {
return DRFLAC_FALSE;
}
bytesRemainingInPage -= 1;
if (packetType == 0x7F) {
/* Increasingly more likely to be a FLAC page... */
drflac_uint8 sig[4];
if (onRead(pUserData, sig, 4) != 4) {
return DRFLAC_FALSE;
}
bytesRemainingInPage -= 4;
share/public_html/static/music_inc/src/dr_flac.h view on Meta::CPAN
/* Unsupported container. */
return DRFLAC_FALSE;
}
static void drflac__init_from_info(drflac* pFlac, const drflac_init_info* pInit)
{
DRFLAC_ASSERT(pFlac != NULL);
DRFLAC_ASSERT(pInit != NULL);
DRFLAC_ZERO_MEMORY(pFlac, sizeof(*pFlac));
pFlac->bs = pInit->bs;
pFlac->onMeta = pInit->onMeta;
pFlac->pUserDataMD = pInit->pUserDataMD;
pFlac->maxBlockSizeInPCMFrames = pInit->maxBlockSizeInPCMFrames;
pFlac->sampleRate = pInit->sampleRate;
pFlac->channels = (drflac_uint8)pInit->channels;
pFlac->bitsPerSample = (drflac_uint8)pInit->bitsPerSample;
pFlac->totalPCMFrameCount = pInit->totalPCMFrameCount;
pFlac->container = pInit->container;
}
static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac_init_info init;
drflac_uint32 allocationSize;
drflac_uint32 wholeSIMDVectorCountPerChannel;
drflac_uint32 decodedSamplesAllocationSize;
#ifndef DR_FLAC_NO_OGG
drflac_oggbs oggbs;
#endif
drflac_uint64 firstFramePos;
drflac_uint64 seektablePos;
drflac_uint32 seektableSize;
drflac_allocation_callbacks allocationCallbacks;
drflac* pFlac;
/* CPU support first. */
drflac__init_cpu_caps();
if (!drflac__init_private(&init, onRead, onSeek, onMeta, container, pUserData, pUserDataMD)) {
return NULL;
}
if (pAllocationCallbacks != NULL) {
allocationCallbacks = *pAllocationCallbacks;
if (allocationCallbacks.onFree == NULL || (allocationCallbacks.onMalloc == NULL && allocationCallbacks.onRealloc == NULL)) {
return NULL; /* Invalid allocation callbacks. */
}
} else {
allocationCallbacks.pUserData = NULL;
allocationCallbacks.onMalloc = drflac__malloc_default;
allocationCallbacks.onRealloc = drflac__realloc_default;
allocationCallbacks.onFree = drflac__free_default;
}
/*
The size of the allocation for the drflac object needs to be large enough to fit the following:
1) The main members of the drflac structure
2) A block of memory large enough to store the decoded samples of the largest frame in the stream
3) If the container is Ogg, a drflac_oggbs object
The complicated part of the allocation is making sure there's enough room the decoded samples, taking into consideration
the different SIMD instruction sets.
*/
allocationSize = sizeof(drflac);
/*
The allocation size for decoded frames depends on the number of 32-bit integers that fit inside the largest SIMD vector
we are supporting.
*/
if ((init.maxBlockSizeInPCMFrames % (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))) == 0) {
wholeSIMDVectorCountPerChannel = (init.maxBlockSizeInPCMFrames / (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32)));
} else {
wholeSIMDVectorCountPerChannel = (init.maxBlockSizeInPCMFrames / (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))) + 1;
}
decodedSamplesAllocationSize = wholeSIMDVectorCountPerChannel * DRFLAC_MAX_SIMD_VECTOR_SIZE * init.channels;
allocationSize += decodedSamplesAllocationSize;
allocationSize += DRFLAC_MAX_SIMD_VECTOR_SIZE; /* Allocate extra bytes to ensure we have enough for alignment. */
#ifndef DR_FLAC_NO_OGG
/* There's additional data required for Ogg streams. */
if (init.container == drflac_container_ogg) {
allocationSize += sizeof(drflac_oggbs);
}
DRFLAC_ZERO_MEMORY(&oggbs, sizeof(oggbs));
if (init.container == drflac_container_ogg) {
oggbs.onRead = onRead;
oggbs.onSeek = onSeek;
oggbs.pUserData = pUserData;
oggbs.currentBytePos = init.oggFirstBytePos;
oggbs.firstBytePos = init.oggFirstBytePos;
oggbs.serialNumber = init.oggSerial;
oggbs.bosPageHeader = init.oggBosHeader;
oggbs.bytesRemainingInPage = 0;
}
#endif
/*
This part is a bit awkward. We need to load the seektable so that it can be referenced in-memory, but I want the drflac object to
consist of only a single heap allocation. To this, the size of the seek table needs to be known, which we determine when reading
and decoding the metadata.
*/
firstFramePos = 42; /* <-- We know we are at byte 42 at this point. */
seektablePos = 0;
seektableSize = 0;
if (init.hasMetadataBlocks) {
drflac_read_proc onReadOverride = onRead;
drflac_seek_proc onSeekOverride = onSeek;
void* pUserDataOverride = pUserData;
#ifndef DR_FLAC_NO_OGG
if (init.container == drflac_container_ogg) {
onReadOverride = drflac__on_read_ogg;
onSeekOverride = drflac__on_seek_ogg;
pUserDataOverride = (void*)&oggbs;
}
#endif
if (!drflac__read_and_decode_metadata(onReadOverride, onSeekOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seektableSize, &allocationCallbacks)) {
return NULL;
}
allocationSize += seektableSize;
}
share/public_html/static/music_inc/src/dr_flac.h view on Meta::CPAN
/* The Ogg bistream needs to be layered on top of the original bitstream. */
pFlac->bs.onRead = drflac__on_read_ogg;
pFlac->bs.onSeek = drflac__on_seek_ogg;
pFlac->bs.pUserData = (void*)pInternalOggbs;
pFlac->_oggbs = (void*)pInternalOggbs;
}
#endif
pFlac->firstFLACFramePosInBytes = firstFramePos;
/* NOTE: Seektables are not currently compatible with Ogg encapsulation (Ogg has its own accelerated seeking system). I may change this later, so I'm leaving this here for now. */
#ifndef DR_FLAC_NO_OGG
if (init.container == drflac_container_ogg)
{
pFlac->pSeekpoints = NULL;
pFlac->seekpointCount = 0;
}
else
#endif
{
/* If we have a seektable we need to load it now, making sure we move back to where we were previously. */
if (seektablePos != 0) {
pFlac->seekpointCount = seektableSize / sizeof(*pFlac->pSeekpoints);
pFlac->pSeekpoints = (drflac_seekpoint*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize);
DRFLAC_ASSERT(pFlac->bs.onSeek != NULL);
DRFLAC_ASSERT(pFlac->bs.onRead != NULL);
/* Seek to the seektable, then just read directly into our seektable buffer. */
if (pFlac->bs.onSeek(pFlac->bs.pUserData, (int)seektablePos, drflac_seek_origin_start)) {
if (pFlac->bs.onRead(pFlac->bs.pUserData, pFlac->pSeekpoints, seektableSize) == seektableSize) {
/* Endian swap. */
drflac_uint32 iSeekpoint;
for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) {
pFlac->pSeekpoints[iSeekpoint].firstPCMFrame = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].firstPCMFrame);
pFlac->pSeekpoints[iSeekpoint].flacFrameOffset = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].flacFrameOffset);
pFlac->pSeekpoints[iSeekpoint].pcmFrameCount = drflac__be2host_16(pFlac->pSeekpoints[iSeekpoint].pcmFrameCount);
}
} else {
/* Failed to read the seektable. Pretend we don't have one. */
pFlac->pSeekpoints = NULL;
pFlac->seekpointCount = 0;
}
/* We need to seek back to where we were. If this fails it's a critical error. */
if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, drflac_seek_origin_start)) {
drflac__free_from_callbacks(pFlac, &allocationCallbacks);
return NULL;
}
} else {
/* Failed to seek to the seektable. Ominous sign, but for now we can just pretend we don't have one. */
pFlac->pSeekpoints = NULL;
pFlac->seekpointCount = 0;
}
}
}
/*
If we get here, but don't have a STREAMINFO block, it means we've opened the stream in relaxed mode and need to decode
the first frame.
*/
if (!init.hasStreamInfoBlock) {
pFlac->currentFLACFrame.header = init.firstFrameHeader;
for (;;) {
drflac_result result = drflac__decode_flac_frame(pFlac);
if (result == DRFLAC_SUCCESS) {
break;
} else {
if (result == DRFLAC_CRC_MISMATCH) {
if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
drflac__free_from_callbacks(pFlac, &allocationCallbacks);
return NULL;
}
continue;
} else {
drflac__free_from_callbacks(pFlac, &allocationCallbacks);
return NULL;
}
}
}
}
return pFlac;
}
#ifndef DR_FLAC_NO_STDIO
#include <stdio.h>
#include <wchar.h> /* For wcslen(), wcsrtombs() */
/* drflac_result_from_errno() is only used for fopen() and wfopen() so putting it inside DR_WAV_NO_STDIO for now. If something else needs this later we can move it out. */
#include <errno.h>
static drflac_result drflac_result_from_errno(int e)
{
switch (e)
{
case 0: return DRFLAC_SUCCESS;
#ifdef EPERM
case EPERM: return DRFLAC_INVALID_OPERATION;
#endif
#ifdef ENOENT
case ENOENT: return DRFLAC_DOES_NOT_EXIST;
#endif
#ifdef ESRCH
case ESRCH: return DRFLAC_DOES_NOT_EXIST;
#endif
#ifdef EINTR
case EINTR: return DRFLAC_INTERRUPT;
#endif
#ifdef EIO
case EIO: return DRFLAC_IO_ERROR;
#endif
#ifdef ENXIO
case ENXIO: return DRFLAC_DOES_NOT_EXIST;
#endif
#ifdef E2BIG
case E2BIG: return DRFLAC_INVALID_ARGS;
#endif
#ifdef ENOEXEC
case ENOEXEC: return DRFLAC_INVALID_FILE;
#endif
#ifdef EBADF
case EBADF: return DRFLAC_INVALID_FILE;
#endif
#ifdef ECHILD
case ECHILD: return DRFLAC_ERROR;
#endif
#ifdef EAGAIN
case EAGAIN: return DRFLAC_UNAVAILABLE;
share/public_html/static/music_inc/src/dr_flac.h view on Meta::CPAN
{
pFlac->bs.pUserData = &pFlac->memoryStream;
}
return pFlac;
}
DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
{
return drflac_open_with_metadata_private(onRead, onSeek, NULL, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks);
}
DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
{
return drflac_open_with_metadata_private(onRead, onSeek, NULL, container, pUserData, pUserData, pAllocationCallbacks);
}
DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
{
return drflac_open_with_metadata_private(onRead, onSeek, onMeta, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks);
}
DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
{
return drflac_open_with_metadata_private(onRead, onSeek, onMeta, container, pUserData, pUserData, pAllocationCallbacks);
}
DRFLAC_API void drflac_close(drflac* pFlac)
{
if (pFlac == NULL) {
return;
}
#ifndef DR_FLAC_NO_STDIO
/*
If we opened the file with drflac_open_file() we will want to close the file handle. We can know whether or not drflac_open_file()
was used by looking at the callbacks.
*/
if (pFlac->bs.onRead == drflac__on_read_stdio) {
fclose((FILE*)pFlac->bs.pUserData);
}
#ifndef DR_FLAC_NO_OGG
/* Need to clean up Ogg streams a bit differently due to the way the bit streaming is chained. */
if (pFlac->container == drflac_container_ogg) {
drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs;
DRFLAC_ASSERT(pFlac->bs.onRead == drflac__on_read_ogg);
if (oggbs->onRead == drflac__on_read_stdio) {
fclose((FILE*)oggbs->pUserData);
}
}
#endif
#endif
drflac__free_from_callbacks(pFlac, &pFlac->allocationCallbacks);
}
#if 0
static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutpu...
{
drflac_uint64 i;
for (i = 0; i < frameCount; ++i) {
drflac_uint32 left = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
drflac_uint32 right = left - side;
pOutputSamples[i*2+0] = (drflac_int32)left;
pOutputSamples[i*2+1] = (drflac_int32)right;
}
}
#endif
static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSa...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
for (i = 0; i < frameCount4; ++i) {
drflac_uint32 left0 = pInputSamples0U32[i*4+0] << shift0;
drflac_uint32 left1 = pInputSamples0U32[i*4+1] << shift0;
drflac_uint32 left2 = pInputSamples0U32[i*4+2] << shift0;
drflac_uint32 left3 = pInputSamples0U32[i*4+3] << shift0;
drflac_uint32 side0 = pInputSamples1U32[i*4+0] << shift1;
drflac_uint32 side1 = pInputSamples1U32[i*4+1] << shift1;
drflac_uint32 side2 = pInputSamples1U32[i*4+2] << shift1;
drflac_uint32 side3 = pInputSamples1U32[i*4+3] << shift1;
drflac_uint32 right0 = left0 - side0;
drflac_uint32 right1 = left1 - side1;
drflac_uint32 right2 = left2 - side2;
drflac_uint32 right3 = left3 - side3;
pOutputSamples[i*8+0] = (drflac_int32)left0;
pOutputSamples[i*8+1] = (drflac_int32)right0;
pOutputSamples[i*8+2] = (drflac_int32)left1;
pOutputSamples[i*8+3] = (drflac_int32)right1;
pOutputSamples[i*8+4] = (drflac_int32)left2;
pOutputSamples[i*8+5] = (drflac_int32)right2;
pOutputSamples[i*8+6] = (drflac_int32)left3;
pOutputSamples[i*8+7] = (drflac_int32)right3;
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 left = pInputSamples0U32[i] << shift0;
drflac_uint32 side = pInputSamples1U32[i] << shift1;
drflac_uint32 right = left - side;
pOutputSamples[i*2+0] = (drflac_int32)left;
pOutputSamples[i*2+1] = (drflac_int32)right;
}
}
#if defined(DRFLAC_SUPPORT_SSE2)
static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamp...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
for (i = 0; i < frameCount4; ++i) {
__m128i left = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
__m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
__m128i right = _mm_sub_epi32(left, side);
_mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right));
_mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 left = pInputSamples0U32[i] << shift0;
drflac_uint32 side = pInputSamples1U32[i] << shift1;
drflac_uint32 right = left - side;
pOutputSamples[i*2+0] = (drflac_int32)left;
pOutputSamples[i*2+1] = (drflac_int32)right;
}
}
#endif
#if defined(DRFLAC_SUPPORT_NEON)
static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamp...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
int32x4_t shift0_4;
int32x4_t shift1_4;
DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
shift0_4 = vdupq_n_s32(shift0);
shift1_4 = vdupq_n_s32(shift1);
for (i = 0; i < frameCount4; ++i) {
uint32x4_t left;
uint32x4_t side;
uint32x4_t right;
left = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
right = vsubq_u32(left, side);
drflac__vst2q_u32((drflac_uint32*)pOutputSamples + i*8, vzipq_u32(left, right));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 left = pInputSamples0U32[i] << shift0;
drflac_uint32 side = pInputSamples1U32[i] << shift1;
drflac_uint32 right = left - side;
pOutputSamples[i*2+0] = (drflac_int32)left;
pOutputSamples[i*2+1] = (drflac_int32)right;
}
}
#endif
static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
{
#if defined(DRFLAC_SUPPORT_SSE2)
if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
drflac_read_pcm_frames_s32__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
} else
#elif defined(DRFLAC_SUPPORT_NEON)
if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
drflac_read_pcm_frames_s32__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
} else
#endif
{
/* Scalar fallback. */
#if 0
drflac_read_pcm_frames_s32__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
#else
drflac_read_pcm_frames_s32__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
#endif
}
}
#if 0
static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutp...
{
drflac_uint64 i;
for (i = 0; i < frameCount; ++i) {
drflac_uint32 side = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
drflac_uint32 right = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
drflac_uint32 left = right + side;
pOutputSamples[i*2+0] = (drflac_int32)left;
pOutputSamples[i*2+1] = (drflac_int32)right;
}
}
#endif
static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputS...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
for (i = 0; i < frameCount4; ++i) {
drflac_uint32 side0 = pInputSamples0U32[i*4+0] << shift0;
drflac_uint32 side1 = pInputSamples0U32[i*4+1] << shift0;
drflac_uint32 side2 = pInputSamples0U32[i*4+2] << shift0;
drflac_uint32 side3 = pInputSamples0U32[i*4+3] << shift0;
drflac_uint32 right0 = pInputSamples1U32[i*4+0] << shift1;
drflac_uint32 right1 = pInputSamples1U32[i*4+1] << shift1;
drflac_uint32 right2 = pInputSamples1U32[i*4+2] << shift1;
drflac_uint32 right3 = pInputSamples1U32[i*4+3] << shift1;
drflac_uint32 left0 = right0 + side0;
drflac_uint32 left1 = right1 + side1;
drflac_uint32 left2 = right2 + side2;
drflac_uint32 left3 = right3 + side3;
pOutputSamples[i*8+0] = (drflac_int32)left0;
pOutputSamples[i*8+1] = (drflac_int32)right0;
pOutputSamples[i*8+2] = (drflac_int32)left1;
pOutputSamples[i*8+3] = (drflac_int32)right1;
pOutputSamples[i*8+4] = (drflac_int32)left2;
pOutputSamples[i*8+5] = (drflac_int32)right2;
pOutputSamples[i*8+6] = (drflac_int32)left3;
pOutputSamples[i*8+7] = (drflac_int32)right3;
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 side = pInputSamples0U32[i] << shift0;
drflac_uint32 right = pInputSamples1U32[i] << shift1;
drflac_uint32 left = right + side;
pOutputSamples[i*2+0] = (drflac_int32)left;
pOutputSamples[i*2+1] = (drflac_int32)right;
}
}
#if defined(DRFLAC_SUPPORT_SSE2)
static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSam...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
for (i = 0; i < frameCount4; ++i) {
__m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
__m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
__m128i left = _mm_add_epi32(right, side);
_mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right));
_mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 side = pInputSamples0U32[i] << shift0;
drflac_uint32 right = pInputSamples1U32[i] << shift1;
drflac_uint32 left = right + side;
pOutputSamples[i*2+0] = (drflac_int32)left;
pOutputSamples[i*2+1] = (drflac_int32)right;
}
}
#endif
#if defined(DRFLAC_SUPPORT_NEON)
static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSam...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
int32x4_t shift0_4;
int32x4_t shift1_4;
DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
shift0_4 = vdupq_n_s32(shift0);
shift1_4 = vdupq_n_s32(shift1);
for (i = 0; i < frameCount4; ++i) {
uint32x4_t side;
uint32x4_t right;
uint32x4_t left;
side = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
right = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
left = vaddq_u32(right, side);
drflac__vst2q_u32((drflac_uint32*)pOutputSamples + i*8, vzipq_u32(left, right));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 side = pInputSamples0U32[i] << shift0;
drflac_uint32 right = pInputSamples1U32[i] << shift1;
drflac_uint32 left = right + side;
pOutputSamples[i*2+0] = (drflac_int32)left;
pOutputSamples[i*2+1] = (drflac_int32)right;
}
}
#endif
static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
{
#if defined(DRFLAC_SUPPORT_SSE2)
if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
drflac_read_pcm_frames_s32__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
} else
#elif defined(DRFLAC_SUPPORT_NEON)
if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
drflac_read_pcm_frames_s32__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
} else
#endif
{
/* Scalar fallback. */
#if 0
drflac_read_pcm_frames_s32__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
#else
drflac_read_pcm_frames_s32__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
#endif
}
}
#if 0
static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutput...
{
for (drflac_uint64 i = 0; i < frameCount; ++i) {
drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
mid = (mid << 1) | (side & 0x01);
pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample);
pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample);
}
}
#endif
static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSam...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_int32 shift = unusedBitsPerSample;
if (shift > 0) {
shift -= 1;
for (i = 0; i < frameCount4; ++i) {
drflac_uint32 temp0L;
drflac_uint32 temp1L;
drflac_uint32 temp2L;
drflac_uint32 temp3L;
drflac_uint32 temp0R;
drflac_uint32 temp1R;
drflac_uint32 temp2R;
drflac_uint32 temp3R;
drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
mid0 = (mid0 << 1) | (side0 & 0x01);
mid1 = (mid1 << 1) | (side1 & 0x01);
mid2 = (mid2 << 1) | (side2 & 0x01);
mid3 = (mid3 << 1) | (side3 & 0x01);
temp0L = (mid0 + side0) << shift;
temp1L = (mid1 + side1) << shift;
temp2L = (mid2 + side2) << shift;
temp3L = (mid3 + side3) << shift;
temp0R = (mid0 - side0) << shift;
temp1R = (mid1 - side1) << shift;
temp2R = (mid2 - side2) << shift;
temp3R = (mid3 - side3) << shift;
pOutputSamples[i*8+0] = (drflac_int32)temp0L;
pOutputSamples[i*8+1] = (drflac_int32)temp0R;
pOutputSamples[i*8+2] = (drflac_int32)temp1L;
pOutputSamples[i*8+3] = (drflac_int32)temp1R;
pOutputSamples[i*8+4] = (drflac_int32)temp2L;
pOutputSamples[i*8+5] = (drflac_int32)temp2R;
pOutputSamples[i*8+6] = (drflac_int32)temp3L;
pOutputSamples[i*8+7] = (drflac_int32)temp3R;
}
} else {
for (i = 0; i < frameCount4; ++i) {
drflac_uint32 temp0L;
drflac_uint32 temp1L;
drflac_uint32 temp2L;
drflac_uint32 temp3L;
drflac_uint32 temp0R;
drflac_uint32 temp1R;
drflac_uint32 temp2R;
drflac_uint32 temp3R;
drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
mid0 = (mid0 << 1) | (side0 & 0x01);
mid1 = (mid1 << 1) | (side1 & 0x01);
mid2 = (mid2 << 1) | (side2 & 0x01);
mid3 = (mid3 << 1) | (side3 & 0x01);
temp0L = (drflac_uint32)((drflac_int32)(mid0 + side0) >> 1);
temp1L = (drflac_uint32)((drflac_int32)(mid1 + side1) >> 1);
temp2L = (drflac_uint32)((drflac_int32)(mid2 + side2) >> 1);
temp3L = (drflac_uint32)((drflac_int32)(mid3 + side3) >> 1);
temp0R = (drflac_uint32)((drflac_int32)(mid0 - side0) >> 1);
temp1R = (drflac_uint32)((drflac_int32)(mid1 - side1) >> 1);
temp2R = (drflac_uint32)((drflac_int32)(mid2 - side2) >> 1);
temp3R = (drflac_uint32)((drflac_int32)(mid3 - side3) >> 1);
pOutputSamples[i*8+0] = (drflac_int32)temp0L;
pOutputSamples[i*8+1] = (drflac_int32)temp0R;
pOutputSamples[i*8+2] = (drflac_int32)temp1L;
pOutputSamples[i*8+3] = (drflac_int32)temp1R;
pOutputSamples[i*8+4] = (drflac_int32)temp2L;
pOutputSamples[i*8+5] = (drflac_int32)temp2R;
pOutputSamples[i*8+6] = (drflac_int32)temp3L;
pOutputSamples[i*8+7] = (drflac_int32)temp3R;
}
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
mid = (mid << 1) | (side & 0x01);
pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample);
pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample);
}
}
#if defined(DRFLAC_SUPPORT_SSE2)
static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSampl...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_int32 shift = unusedBitsPerSample;
DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
if (shift == 0) {
for (i = 0; i < frameCount4; ++i) {
__m128i mid;
__m128i side;
__m128i left;
__m128i right;
mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
left = _mm_srai_epi32(_mm_add_epi32(mid, side), 1);
right = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1);
_mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right));
_mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
mid = (mid << 1) | (side & 0x01);
pOutputSamples[i*2+0] = (drflac_int32)(mid + side) >> 1;
pOutputSamples[i*2+1] = (drflac_int32)(mid - side) >> 1;
}
} else {
shift -= 1;
for (i = 0; i < frameCount4; ++i) {
__m128i mid;
__m128i side;
__m128i left;
__m128i right;
mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
left = _mm_slli_epi32(_mm_add_epi32(mid, side), shift);
right = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift);
_mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right));
_mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
mid = (mid << 1) | (side & 0x01);
pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift);
pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift);
}
}
}
#endif
#if defined(DRFLAC_SUPPORT_NEON)
static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSampl...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_int32 shift = unusedBitsPerSample;
int32x4_t wbpsShift0_4; /* wbps = Wasted Bits Per Sample */
int32x4_t wbpsShift1_4; /* wbps = Wasted Bits Per Sample */
uint32x4_t one4;
DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
wbpsShift0_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
wbpsShift1_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
one4 = vdupq_n_u32(1);
if (shift == 0) {
for (i = 0; i < frameCount4; ++i) {
uint32x4_t mid;
uint32x4_t side;
int32x4_t left;
int32x4_t right;
mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4);
side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4);
mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, one4));
left = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1);
right = vshrq_n_s32(vreinterpretq_s32_u32(vsubq_u32(mid, side)), 1);
drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
mid = (mid << 1) | (side & 0x01);
pOutputSamples[i*2+0] = (drflac_int32)(mid + side) >> 1;
pOutputSamples[i*2+1] = (drflac_int32)(mid - side) >> 1;
}
} else {
int32x4_t shift4;
shift -= 1;
shift4 = vdupq_n_s32(shift);
for (i = 0; i < frameCount4; ++i) {
uint32x4_t mid;
uint32x4_t side;
int32x4_t left;
int32x4_t right;
mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4);
side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4);
mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, one4));
left = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4));
right = vreinterpretq_s32_u32(vshlq_u32(vsubq_u32(mid, side), shift4));
drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
mid = (mid << 1) | (side & 0x01);
pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift);
pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift);
}
}
}
#endif
static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
{
#if defined(DRFLAC_SUPPORT_SSE2)
if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
drflac_read_pcm_frames_s32__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
} else
#elif defined(DRFLAC_SUPPORT_NEON)
if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
drflac_read_pcm_frames_s32__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
} else
#endif
{
/* Scalar fallback. */
#if 0
drflac_read_pcm_frames_s32__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
#else
drflac_read_pcm_frames_s32__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
#endif
}
}
#if 0
static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int3...
{
for (drflac_uint64 i = 0; i < frameCount; ++i) {
pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample));
pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample));
}
}
#endif
static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* ...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
for (i = 0; i < frameCount4; ++i) {
drflac_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0;
drflac_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0;
drflac_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0;
drflac_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0;
drflac_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1;
drflac_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1;
drflac_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1;
drflac_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1;
pOutputSamples[i*8+0] = (drflac_int32)tempL0;
pOutputSamples[i*8+1] = (drflac_int32)tempR0;
pOutputSamples[i*8+2] = (drflac_int32)tempL1;
pOutputSamples[i*8+3] = (drflac_int32)tempR1;
pOutputSamples[i*8+4] = (drflac_int32)tempL2;
pOutputSamples[i*8+5] = (drflac_int32)tempR2;
pOutputSamples[i*8+6] = (drflac_int32)tempL3;
pOutputSamples[i*8+7] = (drflac_int32)tempR3;
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0);
pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1);
}
}
#if defined(DRFLAC_SUPPORT_SSE2)
static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pO...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
for (i = 0; i < frameCount4; ++i) {
__m128i left = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
__m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
_mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right));
_mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0);
pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1);
}
}
#endif
#if defined(DRFLAC_SUPPORT_NEON)
static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pO...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
int32x4_t shift4_0 = vdupq_n_s32(shift0);
int32x4_t shift4_1 = vdupq_n_s32(shift1);
for (i = 0; i < frameCount4; ++i) {
int32x4_t left;
int32x4_t right;
left = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift4_0));
right = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift4_1));
drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0);
pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1);
}
}
#endif
static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputS...
{
#if defined(DRFLAC_SUPPORT_SSE2)
if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
drflac_read_pcm_frames_s32__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
} else
#elif defined(DRFLAC_SUPPORT_NEON)
if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
drflac_read_pcm_frames_s32__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
} else
#endif
{
/* Scalar fallback. */
#if 0
drflac_read_pcm_frames_s32__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
#else
drflac_read_pcm_frames_s32__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
#endif
}
}
DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s32(drflac* pFlac, drflac_uint64 framesToRead, drflac_int32* pBufferOut)
{
drflac_uint64 framesRead;
drflac_uint32 unusedBitsPerSample;
if (pFlac == NULL || framesToRead == 0) {
return 0;
}
if (pBufferOut == NULL) {
return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead);
}
DRFLAC_ASSERT(pFlac->bitsPerSample <= 32);
unusedBitsPerSample = 32 - pFlac->bitsPerSample;
framesRead = 0;
while (framesToRead > 0) {
/* If we've run out of samples in this frame, go to the next. */
if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
if (!drflac__read_and_decode_next_flac_frame(pFlac)) {
break; /* Couldn't read the next frame, so just break from the loop and return. */
}
} else {
unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment);
drflac_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining;
drflac_uint64 frameCountThisIteration = framesToRead;
if (frameCountThisIteration > pFlac->currentFLACFrame.pcmFramesRemaining) {
frameCountThisIteration = pFlac->currentFLACFrame.pcmFramesRemaining;
}
if (channelCount == 2) {
const drflac_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame;
const drflac_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame;
switch (pFlac->currentFLACFrame.header.channelAssignment)
{
case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE:
{
drflac_read_pcm_frames_s32__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
} break;
case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE:
{
drflac_read_pcm_frames_s32__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
} break;
case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE:
{
drflac_read_pcm_frames_s32__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
} break;
case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT:
default:
{
drflac_read_pcm_frames_s32__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
} break;
}
} else {
/* Generic interleaving. */
drflac_uint64 i;
for (i = 0; i < frameCountThisIteration; ++i) {
unsigned int j;
for (j = 0; j < channelCount; ++j) {
pBufferOut[(i*channelCount)+j] = (drflac_int32)((drflac_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample));
}
}
}
framesRead += frameCountThisIteration;
pBufferOut += frameCountThisIteration * channelCount;
framesToRead -= frameCountThisIteration;
pFlac->currentPCMFrame += frameCountThisIteration;
pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)frameCountThisIteration;
}
}
return framesRead;
}
#if 0
static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutpu...
{
drflac_uint64 i;
for (i = 0; i < frameCount; ++i) {
drflac_uint32 left = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
drflac_uint32 right = left - side;
left >>= 16;
right >>= 16;
pOutputSamples[i*2+0] = (drflac_int16)left;
pOutputSamples[i*2+1] = (drflac_int16)right;
}
}
#endif
static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSa...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
for (i = 0; i < frameCount4; ++i) {
drflac_uint32 left0 = pInputSamples0U32[i*4+0] << shift0;
drflac_uint32 left1 = pInputSamples0U32[i*4+1] << shift0;
drflac_uint32 left2 = pInputSamples0U32[i*4+2] << shift0;
drflac_uint32 left3 = pInputSamples0U32[i*4+3] << shift0;
drflac_uint32 side0 = pInputSamples1U32[i*4+0] << shift1;
drflac_uint32 side1 = pInputSamples1U32[i*4+1] << shift1;
drflac_uint32 side2 = pInputSamples1U32[i*4+2] << shift1;
drflac_uint32 side3 = pInputSamples1U32[i*4+3] << shift1;
drflac_uint32 right0 = left0 - side0;
drflac_uint32 right1 = left1 - side1;
drflac_uint32 right2 = left2 - side2;
drflac_uint32 right3 = left3 - side3;
left0 >>= 16;
left1 >>= 16;
left2 >>= 16;
left3 >>= 16;
right0 >>= 16;
right1 >>= 16;
right2 >>= 16;
right3 >>= 16;
pOutputSamples[i*8+0] = (drflac_int16)left0;
pOutputSamples[i*8+1] = (drflac_int16)right0;
pOutputSamples[i*8+2] = (drflac_int16)left1;
pOutputSamples[i*8+3] = (drflac_int16)right1;
pOutputSamples[i*8+4] = (drflac_int16)left2;
pOutputSamples[i*8+5] = (drflac_int16)right2;
pOutputSamples[i*8+6] = (drflac_int16)left3;
pOutputSamples[i*8+7] = (drflac_int16)right3;
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 left = pInputSamples0U32[i] << shift0;
drflac_uint32 side = pInputSamples1U32[i] << shift1;
drflac_uint32 right = left - side;
left >>= 16;
right >>= 16;
pOutputSamples[i*2+0] = (drflac_int16)left;
pOutputSamples[i*2+1] = (drflac_int16)right;
}
}
#if defined(DRFLAC_SUPPORT_SSE2)
static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamp...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
for (i = 0; i < frameCount4; ++i) {
__m128i left = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
__m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
__m128i right = _mm_sub_epi32(left, side);
left = _mm_srai_epi32(left, 16);
right = _mm_srai_epi32(right, 16);
_mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 left = pInputSamples0U32[i] << shift0;
drflac_uint32 side = pInputSamples1U32[i] << shift1;
drflac_uint32 right = left - side;
left >>= 16;
right >>= 16;
pOutputSamples[i*2+0] = (drflac_int16)left;
pOutputSamples[i*2+1] = (drflac_int16)right;
}
}
#endif
#if defined(DRFLAC_SUPPORT_NEON)
static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamp...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
int32x4_t shift0_4;
int32x4_t shift1_4;
DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
shift0_4 = vdupq_n_s32(shift0);
shift1_4 = vdupq_n_s32(shift1);
for (i = 0; i < frameCount4; ++i) {
uint32x4_t left;
uint32x4_t side;
uint32x4_t right;
left = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
right = vsubq_u32(left, side);
left = vshrq_n_u32(left, 16);
right = vshrq_n_u32(right, 16);
drflac__vst2q_u16((drflac_uint16*)pOutputSamples + i*8, vzip_u16(vmovn_u32(left), vmovn_u32(right)));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 left = pInputSamples0U32[i] << shift0;
drflac_uint32 side = pInputSamples1U32[i] << shift1;
drflac_uint32 right = left - side;
left >>= 16;
right >>= 16;
pOutputSamples[i*2+0] = (drflac_int16)left;
pOutputSamples[i*2+1] = (drflac_int16)right;
}
}
#endif
static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
{
#if defined(DRFLAC_SUPPORT_SSE2)
if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
drflac_read_pcm_frames_s16__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
} else
#elif defined(DRFLAC_SUPPORT_NEON)
if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
drflac_read_pcm_frames_s16__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
} else
#endif
{
/* Scalar fallback. */
#if 0
drflac_read_pcm_frames_s16__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
#else
drflac_read_pcm_frames_s16__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
#endif
}
}
#if 0
static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutp...
{
drflac_uint64 i;
for (i = 0; i < frameCount; ++i) {
drflac_uint32 side = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
drflac_uint32 right = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
drflac_uint32 left = right + side;
left >>= 16;
right >>= 16;
pOutputSamples[i*2+0] = (drflac_int16)left;
pOutputSamples[i*2+1] = (drflac_int16)right;
}
}
#endif
static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputS...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
for (i = 0; i < frameCount4; ++i) {
drflac_uint32 side0 = pInputSamples0U32[i*4+0] << shift0;
drflac_uint32 side1 = pInputSamples0U32[i*4+1] << shift0;
drflac_uint32 side2 = pInputSamples0U32[i*4+2] << shift0;
drflac_uint32 side3 = pInputSamples0U32[i*4+3] << shift0;
drflac_uint32 right0 = pInputSamples1U32[i*4+0] << shift1;
drflac_uint32 right1 = pInputSamples1U32[i*4+1] << shift1;
drflac_uint32 right2 = pInputSamples1U32[i*4+2] << shift1;
drflac_uint32 right3 = pInputSamples1U32[i*4+3] << shift1;
drflac_uint32 left0 = right0 + side0;
drflac_uint32 left1 = right1 + side1;
drflac_uint32 left2 = right2 + side2;
drflac_uint32 left3 = right3 + side3;
left0 >>= 16;
left1 >>= 16;
left2 >>= 16;
left3 >>= 16;
right0 >>= 16;
right1 >>= 16;
right2 >>= 16;
right3 >>= 16;
pOutputSamples[i*8+0] = (drflac_int16)left0;
pOutputSamples[i*8+1] = (drflac_int16)right0;
pOutputSamples[i*8+2] = (drflac_int16)left1;
pOutputSamples[i*8+3] = (drflac_int16)right1;
pOutputSamples[i*8+4] = (drflac_int16)left2;
pOutputSamples[i*8+5] = (drflac_int16)right2;
pOutputSamples[i*8+6] = (drflac_int16)left3;
pOutputSamples[i*8+7] = (drflac_int16)right3;
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 side = pInputSamples0U32[i] << shift0;
drflac_uint32 right = pInputSamples1U32[i] << shift1;
drflac_uint32 left = right + side;
left >>= 16;
right >>= 16;
pOutputSamples[i*2+0] = (drflac_int16)left;
pOutputSamples[i*2+1] = (drflac_int16)right;
}
}
#if defined(DRFLAC_SUPPORT_SSE2)
static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSam...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
for (i = 0; i < frameCount4; ++i) {
__m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
__m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
__m128i left = _mm_add_epi32(right, side);
left = _mm_srai_epi32(left, 16);
right = _mm_srai_epi32(right, 16);
_mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 side = pInputSamples0U32[i] << shift0;
drflac_uint32 right = pInputSamples1U32[i] << shift1;
drflac_uint32 left = right + side;
left >>= 16;
right >>= 16;
pOutputSamples[i*2+0] = (drflac_int16)left;
pOutputSamples[i*2+1] = (drflac_int16)right;
}
}
#endif
#if defined(DRFLAC_SUPPORT_NEON)
static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSam...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
int32x4_t shift0_4;
int32x4_t shift1_4;
DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
shift0_4 = vdupq_n_s32(shift0);
shift1_4 = vdupq_n_s32(shift1);
for (i = 0; i < frameCount4; ++i) {
uint32x4_t side;
uint32x4_t right;
uint32x4_t left;
side = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
right = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
left = vaddq_u32(right, side);
left = vshrq_n_u32(left, 16);
right = vshrq_n_u32(right, 16);
drflac__vst2q_u16((drflac_uint16*)pOutputSamples + i*8, vzip_u16(vmovn_u32(left), vmovn_u32(right)));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 side = pInputSamples0U32[i] << shift0;
drflac_uint32 right = pInputSamples1U32[i] << shift1;
drflac_uint32 left = right + side;
left >>= 16;
right >>= 16;
pOutputSamples[i*2+0] = (drflac_int16)left;
pOutputSamples[i*2+1] = (drflac_int16)right;
}
}
#endif
static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
{
#if defined(DRFLAC_SUPPORT_SSE2)
if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
drflac_read_pcm_frames_s16__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
} else
#elif defined(DRFLAC_SUPPORT_NEON)
if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
drflac_read_pcm_frames_s16__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
} else
#endif
{
/* Scalar fallback. */
#if 0
drflac_read_pcm_frames_s16__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
#else
drflac_read_pcm_frames_s16__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
#endif
}
}
#if 0
static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutput...
{
for (drflac_uint64 i = 0; i < frameCount; ++i) {
drflac_uint32 mid = (drflac_uint32)pInputSamples0[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
mid = (mid << 1) | (side & 0x01);
pOutputSamples[i*2+0] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample) >> 16);
pOutputSamples[i*2+1] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample) >> 16);
}
}
#endif
static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSam...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift = unusedBitsPerSample;
if (shift > 0) {
shift -= 1;
for (i = 0; i < frameCount4; ++i) {
drflac_uint32 temp0L;
drflac_uint32 temp1L;
drflac_uint32 temp2L;
drflac_uint32 temp3L;
drflac_uint32 temp0R;
drflac_uint32 temp1R;
drflac_uint32 temp2R;
drflac_uint32 temp3R;
drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
mid0 = (mid0 << 1) | (side0 & 0x01);
mid1 = (mid1 << 1) | (side1 & 0x01);
mid2 = (mid2 << 1) | (side2 & 0x01);
mid3 = (mid3 << 1) | (side3 & 0x01);
temp0L = (mid0 + side0) << shift;
temp1L = (mid1 + side1) << shift;
temp2L = (mid2 + side2) << shift;
temp3L = (mid3 + side3) << shift;
temp0R = (mid0 - side0) << shift;
temp1R = (mid1 - side1) << shift;
temp2R = (mid2 - side2) << shift;
temp3R = (mid3 - side3) << shift;
temp0L >>= 16;
temp1L >>= 16;
temp2L >>= 16;
temp3L >>= 16;
temp0R >>= 16;
temp1R >>= 16;
temp2R >>= 16;
temp3R >>= 16;
pOutputSamples[i*8+0] = (drflac_int16)temp0L;
pOutputSamples[i*8+1] = (drflac_int16)temp0R;
pOutputSamples[i*8+2] = (drflac_int16)temp1L;
pOutputSamples[i*8+3] = (drflac_int16)temp1R;
pOutputSamples[i*8+4] = (drflac_int16)temp2L;
pOutputSamples[i*8+5] = (drflac_int16)temp2R;
pOutputSamples[i*8+6] = (drflac_int16)temp3L;
pOutputSamples[i*8+7] = (drflac_int16)temp3R;
}
} else {
for (i = 0; i < frameCount4; ++i) {
drflac_uint32 temp0L;
drflac_uint32 temp1L;
drflac_uint32 temp2L;
drflac_uint32 temp3L;
drflac_uint32 temp0R;
drflac_uint32 temp1R;
drflac_uint32 temp2R;
drflac_uint32 temp3R;
drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
mid0 = (mid0 << 1) | (side0 & 0x01);
mid1 = (mid1 << 1) | (side1 & 0x01);
mid2 = (mid2 << 1) | (side2 & 0x01);
mid3 = (mid3 << 1) | (side3 & 0x01);
temp0L = ((drflac_int32)(mid0 + side0) >> 1);
temp1L = ((drflac_int32)(mid1 + side1) >> 1);
temp2L = ((drflac_int32)(mid2 + side2) >> 1);
temp3L = ((drflac_int32)(mid3 + side3) >> 1);
temp0R = ((drflac_int32)(mid0 - side0) >> 1);
temp1R = ((drflac_int32)(mid1 - side1) >> 1);
temp2R = ((drflac_int32)(mid2 - side2) >> 1);
temp3R = ((drflac_int32)(mid3 - side3) >> 1);
temp0L >>= 16;
temp1L >>= 16;
temp2L >>= 16;
temp3L >>= 16;
temp0R >>= 16;
temp1R >>= 16;
temp2R >>= 16;
temp3R >>= 16;
pOutputSamples[i*8+0] = (drflac_int16)temp0L;
pOutputSamples[i*8+1] = (drflac_int16)temp0R;
pOutputSamples[i*8+2] = (drflac_int16)temp1L;
pOutputSamples[i*8+3] = (drflac_int16)temp1R;
pOutputSamples[i*8+4] = (drflac_int16)temp2L;
pOutputSamples[i*8+5] = (drflac_int16)temp2R;
pOutputSamples[i*8+6] = (drflac_int16)temp3L;
pOutputSamples[i*8+7] = (drflac_int16)temp3R;
}
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
mid = (mid << 1) | (side & 0x01);
pOutputSamples[i*2+0] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample) >> 16);
pOutputSamples[i*2+1] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample) >> 16);
}
}
#if defined(DRFLAC_SUPPORT_SSE2)
static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSampl...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift = unusedBitsPerSample;
DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
if (shift == 0) {
for (i = 0; i < frameCount4; ++i) {
__m128i mid;
__m128i side;
__m128i left;
__m128i right;
mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
left = _mm_srai_epi32(_mm_add_epi32(mid, side), 1);
right = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1);
left = _mm_srai_epi32(left, 16);
right = _mm_srai_epi32(right, 16);
_mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
mid = (mid << 1) | (side & 0x01);
pOutputSamples[i*2+0] = (drflac_int16)(((drflac_int32)(mid + side) >> 1) >> 16);
pOutputSamples[i*2+1] = (drflac_int16)(((drflac_int32)(mid - side) >> 1) >> 16);
}
} else {
shift -= 1;
for (i = 0; i < frameCount4; ++i) {
__m128i mid;
__m128i side;
__m128i left;
__m128i right;
mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
left = _mm_slli_epi32(_mm_add_epi32(mid, side), shift);
right = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift);
left = _mm_srai_epi32(left, 16);
right = _mm_srai_epi32(right, 16);
_mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
mid = (mid << 1) | (side & 0x01);
pOutputSamples[i*2+0] = (drflac_int16)(((mid + side) << shift) >> 16);
pOutputSamples[i*2+1] = (drflac_int16)(((mid - side) << shift) >> 16);
}
}
}
#endif
#if defined(DRFLAC_SUPPORT_NEON)
static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSampl...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift = unusedBitsPerSample;
int32x4_t wbpsShift0_4; /* wbps = Wasted Bits Per Sample */
int32x4_t wbpsShift1_4; /* wbps = Wasted Bits Per Sample */
DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
wbpsShift0_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
wbpsShift1_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
if (shift == 0) {
for (i = 0; i < frameCount4; ++i) {
uint32x4_t mid;
uint32x4_t side;
int32x4_t left;
int32x4_t right;
mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4);
side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4);
mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1)));
left = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1);
right = vshrq_n_s32(vreinterpretq_s32_u32(vsubq_u32(mid, side)), 1);
left = vshrq_n_s32(left, 16);
right = vshrq_n_s32(right, 16);
drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right)));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
mid = (mid << 1) | (side & 0x01);
pOutputSamples[i*2+0] = (drflac_int16)(((drflac_int32)(mid + side) >> 1) >> 16);
pOutputSamples[i*2+1] = (drflac_int16)(((drflac_int32)(mid - side) >> 1) >> 16);
}
} else {
int32x4_t shift4;
shift -= 1;
shift4 = vdupq_n_s32(shift);
for (i = 0; i < frameCount4; ++i) {
uint32x4_t mid;
uint32x4_t side;
int32x4_t left;
int32x4_t right;
mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4);
side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4);
mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1)));
left = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4));
right = vreinterpretq_s32_u32(vshlq_u32(vsubq_u32(mid, side), shift4));
left = vshrq_n_s32(left, 16);
right = vshrq_n_s32(right, 16);
drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right)));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
mid = (mid << 1) | (side & 0x01);
pOutputSamples[i*2+0] = (drflac_int16)(((mid + side) << shift) >> 16);
pOutputSamples[i*2+1] = (drflac_int16)(((mid - side) << shift) >> 16);
}
}
}
#endif
static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
{
#if defined(DRFLAC_SUPPORT_SSE2)
if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
drflac_read_pcm_frames_s16__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
} else
#elif defined(DRFLAC_SUPPORT_NEON)
if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
drflac_read_pcm_frames_s16__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
} else
#endif
{
/* Scalar fallback. */
#if 0
drflac_read_pcm_frames_s16__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
#else
drflac_read_pcm_frames_s16__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
#endif
}
}
#if 0
static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int1...
{
for (drflac_uint64 i = 0; i < frameCount; ++i) {
pOutputSamples[i*2+0] = (drflac_int16)((drflac_int32)((drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample)) >> 16);
pOutputSamples[i*2+1] = (drflac_int16)((drflac_int32)((drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample)) >> 16);
}
}
#endif
static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* ...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
for (i = 0; i < frameCount4; ++i) {
drflac_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0;
drflac_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0;
drflac_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0;
drflac_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0;
drflac_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1;
drflac_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1;
drflac_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1;
drflac_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1;
tempL0 >>= 16;
tempL1 >>= 16;
tempL2 >>= 16;
tempL3 >>= 16;
tempR0 >>= 16;
tempR1 >>= 16;
tempR2 >>= 16;
tempR3 >>= 16;
pOutputSamples[i*8+0] = (drflac_int16)tempL0;
pOutputSamples[i*8+1] = (drflac_int16)tempR0;
pOutputSamples[i*8+2] = (drflac_int16)tempL1;
pOutputSamples[i*8+3] = (drflac_int16)tempR1;
pOutputSamples[i*8+4] = (drflac_int16)tempL2;
pOutputSamples[i*8+5] = (drflac_int16)tempR2;
pOutputSamples[i*8+6] = (drflac_int16)tempL3;
pOutputSamples[i*8+7] = (drflac_int16)tempR3;
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
pOutputSamples[i*2+0] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16);
pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16);
}
}
#if defined(DRFLAC_SUPPORT_SSE2)
static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pO...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
for (i = 0; i < frameCount4; ++i) {
__m128i left = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
__m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
left = _mm_srai_epi32(left, 16);
right = _mm_srai_epi32(right, 16);
/* At this point we have results. We can now pack and interleave these into a single __m128i object and then store the in the output buffer. */
_mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
pOutputSamples[i*2+0] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16);
pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16);
}
}
#endif
#if defined(DRFLAC_SUPPORT_NEON)
static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pO...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
int32x4_t shift0_4 = vdupq_n_s32(shift0);
int32x4_t shift1_4 = vdupq_n_s32(shift1);
for (i = 0; i < frameCount4; ++i) {
int32x4_t left;
int32x4_t right;
left = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4));
right = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4));
left = vshrq_n_s32(left, 16);
right = vshrq_n_s32(right, 16);
drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right)));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
pOutputSamples[i*2+0] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16);
pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16);
}
}
#endif
static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputS...
{
#if defined(DRFLAC_SUPPORT_SSE2)
if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
drflac_read_pcm_frames_s16__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
} else
#elif defined(DRFLAC_SUPPORT_NEON)
if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
drflac_read_pcm_frames_s16__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
} else
#endif
{
/* Scalar fallback. */
#if 0
drflac_read_pcm_frames_s16__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
#else
drflac_read_pcm_frames_s16__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
#endif
}
}
DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s16(drflac* pFlac, drflac_uint64 framesToRead, drflac_int16* pBufferOut)
{
drflac_uint64 framesRead;
drflac_uint32 unusedBitsPerSample;
if (pFlac == NULL || framesToRead == 0) {
return 0;
}
if (pBufferOut == NULL) {
return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead);
}
DRFLAC_ASSERT(pFlac->bitsPerSample <= 32);
unusedBitsPerSample = 32 - pFlac->bitsPerSample;
framesRead = 0;
while (framesToRead > 0) {
/* If we've run out of samples in this frame, go to the next. */
if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
if (!drflac__read_and_decode_next_flac_frame(pFlac)) {
break; /* Couldn't read the next frame, so just break from the loop and return. */
}
} else {
unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment);
drflac_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining;
drflac_uint64 frameCountThisIteration = framesToRead;
if (frameCountThisIteration > pFlac->currentFLACFrame.pcmFramesRemaining) {
frameCountThisIteration = pFlac->currentFLACFrame.pcmFramesRemaining;
}
if (channelCount == 2) {
const drflac_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame;
const drflac_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame;
switch (pFlac->currentFLACFrame.header.channelAssignment)
{
case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE:
{
drflac_read_pcm_frames_s16__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
} break;
case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE:
{
drflac_read_pcm_frames_s16__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
} break;
case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE:
{
drflac_read_pcm_frames_s16__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
} break;
case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT:
default:
{
drflac_read_pcm_frames_s16__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
} break;
}
} else {
/* Generic interleaving. */
drflac_uint64 i;
for (i = 0; i < frameCountThisIteration; ++i) {
unsigned int j;
for (j = 0; j < channelCount; ++j) {
drflac_int32 sampleS32 = (drflac_int32)((drflac_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample));
pBufferOut[(i*channelCount)+j] = (drflac_int16)(sampleS32 >> 16);
}
}
}
framesRead += frameCountThisIteration;
pBufferOut += frameCountThisIteration * channelCount;
framesToRead -= frameCountThisIteration;
pFlac->currentPCMFrame += frameCountThisIteration;
pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)frameCountThisIteration;
}
}
return framesRead;
}
#if 0
static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSample...
{
drflac_uint64 i;
for (i = 0; i < frameCount; ++i) {
drflac_uint32 left = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
drflac_uint32 right = left - side;
pOutputSamples[i*2+0] = (float)((drflac_int32)left / 2147483648.0);
pOutputSamples[i*2+1] = (float)((drflac_int32)right / 2147483648.0);
}
}
#endif
static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
float factor = 1 / 2147483648.0;
for (i = 0; i < frameCount4; ++i) {
drflac_uint32 left0 = pInputSamples0U32[i*4+0] << shift0;
drflac_uint32 left1 = pInputSamples0U32[i*4+1] << shift0;
drflac_uint32 left2 = pInputSamples0U32[i*4+2] << shift0;
drflac_uint32 left3 = pInputSamples0U32[i*4+3] << shift0;
drflac_uint32 side0 = pInputSamples1U32[i*4+0] << shift1;
drflac_uint32 side1 = pInputSamples1U32[i*4+1] << shift1;
drflac_uint32 side2 = pInputSamples1U32[i*4+2] << shift1;
drflac_uint32 side3 = pInputSamples1U32[i*4+3] << shift1;
drflac_uint32 right0 = left0 - side0;
drflac_uint32 right1 = left1 - side1;
drflac_uint32 right2 = left2 - side2;
drflac_uint32 right3 = left3 - side3;
pOutputSamples[i*8+0] = (drflac_int32)left0 * factor;
pOutputSamples[i*8+1] = (drflac_int32)right0 * factor;
pOutputSamples[i*8+2] = (drflac_int32)left1 * factor;
pOutputSamples[i*8+3] = (drflac_int32)right1 * factor;
pOutputSamples[i*8+4] = (drflac_int32)left2 * factor;
pOutputSamples[i*8+5] = (drflac_int32)right2 * factor;
pOutputSamples[i*8+6] = (drflac_int32)left3 * factor;
pOutputSamples[i*8+7] = (drflac_int32)right3 * factor;
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 left = pInputSamples0U32[i] << shift0;
drflac_uint32 side = pInputSamples1U32[i] << shift1;
drflac_uint32 right = left - side;
pOutputSamples[i*2+0] = (drflac_int32)left * factor;
pOutputSamples[i*2+1] = (drflac_int32)right * factor;
}
}
#if defined(DRFLAC_SUPPORT_SSE2)
static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
__m128 factor;
DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
factor = _mm_set1_ps(1.0f / 8388608.0f);
for (i = 0; i < frameCount4; ++i) {
__m128i left = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
__m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
__m128i right = _mm_sub_epi32(left, side);
__m128 leftf = _mm_mul_ps(_mm_cvtepi32_ps(left), factor);
__m128 rightf = _mm_mul_ps(_mm_cvtepi32_ps(right), factor);
_mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf));
_mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 left = pInputSamples0U32[i] << shift0;
drflac_uint32 side = pInputSamples1U32[i] << shift1;
drflac_uint32 right = left - side;
pOutputSamples[i*2+0] = (drflac_int32)left / 8388608.0f;
pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f;
}
}
#endif
#if defined(DRFLAC_SUPPORT_NEON)
static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
float32x4_t factor4;
int32x4_t shift0_4;
int32x4_t shift1_4;
DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
factor4 = vdupq_n_f32(1.0f / 8388608.0f);
shift0_4 = vdupq_n_s32(shift0);
shift1_4 = vdupq_n_s32(shift1);
for (i = 0; i < frameCount4; ++i) {
uint32x4_t left;
uint32x4_t side;
uint32x4_t right;
float32x4_t leftf;
float32x4_t rightf;
left = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
right = vsubq_u32(left, side);
leftf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(left)), factor4);
rightf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(right)), factor4);
drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 left = pInputSamples0U32[i] << shift0;
drflac_uint32 side = pInputSamples1U32[i] << shift1;
drflac_uint32 right = left - side;
pOutputSamples[i*2+0] = (drflac_int32)left / 8388608.0f;
pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f;
}
}
#endif
static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
{
#if defined(DRFLAC_SUPPORT_SSE2)
if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
drflac_read_pcm_frames_f32__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
} else
#elif defined(DRFLAC_SUPPORT_NEON)
if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
drflac_read_pcm_frames_f32__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
} else
#endif
{
/* Scalar fallback. */
#if 0
drflac_read_pcm_frames_f32__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
#else
drflac_read_pcm_frames_f32__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
#endif
}
}
#if 0
static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSampl...
{
drflac_uint64 i;
for (i = 0; i < frameCount; ++i) {
drflac_uint32 side = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
drflac_uint32 right = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
drflac_uint32 left = right + side;
pOutputSamples[i*2+0] = (float)((drflac_int32)left / 2147483648.0);
pOutputSamples[i*2+1] = (float)((drflac_int32)right / 2147483648.0);
}
}
#endif
static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
float factor = 1 / 2147483648.0;
for (i = 0; i < frameCount4; ++i) {
drflac_uint32 side0 = pInputSamples0U32[i*4+0] << shift0;
drflac_uint32 side1 = pInputSamples0U32[i*4+1] << shift0;
drflac_uint32 side2 = pInputSamples0U32[i*4+2] << shift0;
drflac_uint32 side3 = pInputSamples0U32[i*4+3] << shift0;
drflac_uint32 right0 = pInputSamples1U32[i*4+0] << shift1;
drflac_uint32 right1 = pInputSamples1U32[i*4+1] << shift1;
drflac_uint32 right2 = pInputSamples1U32[i*4+2] << shift1;
drflac_uint32 right3 = pInputSamples1U32[i*4+3] << shift1;
drflac_uint32 left0 = right0 + side0;
drflac_uint32 left1 = right1 + side1;
drflac_uint32 left2 = right2 + side2;
drflac_uint32 left3 = right3 + side3;
pOutputSamples[i*8+0] = (drflac_int32)left0 * factor;
pOutputSamples[i*8+1] = (drflac_int32)right0 * factor;
pOutputSamples[i*8+2] = (drflac_int32)left1 * factor;
pOutputSamples[i*8+3] = (drflac_int32)right1 * factor;
pOutputSamples[i*8+4] = (drflac_int32)left2 * factor;
pOutputSamples[i*8+5] = (drflac_int32)right2 * factor;
pOutputSamples[i*8+6] = (drflac_int32)left3 * factor;
pOutputSamples[i*8+7] = (drflac_int32)right3 * factor;
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 side = pInputSamples0U32[i] << shift0;
drflac_uint32 right = pInputSamples1U32[i] << shift1;
drflac_uint32 left = right + side;
pOutputSamples[i*2+0] = (drflac_int32)left * factor;
pOutputSamples[i*2+1] = (drflac_int32)right * factor;
}
}
#if defined(DRFLAC_SUPPORT_SSE2)
static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
__m128 factor;
DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
factor = _mm_set1_ps(1.0f / 8388608.0f);
for (i = 0; i < frameCount4; ++i) {
__m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
__m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
__m128i left = _mm_add_epi32(right, side);
__m128 leftf = _mm_mul_ps(_mm_cvtepi32_ps(left), factor);
__m128 rightf = _mm_mul_ps(_mm_cvtepi32_ps(right), factor);
_mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf));
_mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 side = pInputSamples0U32[i] << shift0;
drflac_uint32 right = pInputSamples1U32[i] << shift1;
drflac_uint32 left = right + side;
pOutputSamples[i*2+0] = (drflac_int32)left / 8388608.0f;
pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f;
}
}
#endif
#if defined(DRFLAC_SUPPORT_NEON)
static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
float32x4_t factor4;
int32x4_t shift0_4;
int32x4_t shift1_4;
DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
factor4 = vdupq_n_f32(1.0f / 8388608.0f);
shift0_4 = vdupq_n_s32(shift0);
shift1_4 = vdupq_n_s32(shift1);
for (i = 0; i < frameCount4; ++i) {
uint32x4_t side;
uint32x4_t right;
uint32x4_t left;
float32x4_t leftf;
float32x4_t rightf;
side = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
right = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
left = vaddq_u32(right, side);
leftf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(left)), factor4);
rightf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(right)), factor4);
drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 side = pInputSamples0U32[i] << shift0;
drflac_uint32 right = pInputSamples1U32[i] << shift1;
drflac_uint32 left = right + side;
pOutputSamples[i*2+0] = (drflac_int32)left / 8388608.0f;
pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f;
}
}
#endif
static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
{
#if defined(DRFLAC_SUPPORT_SSE2)
if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
drflac_read_pcm_frames_f32__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
} else
#elif defined(DRFLAC_SUPPORT_NEON)
if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
drflac_read_pcm_frames_f32__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
} else
#endif
{
/* Scalar fallback. */
#if 0
drflac_read_pcm_frames_f32__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
#else
drflac_read_pcm_frames_f32__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
#endif
}
}
#if 0
static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples...
{
for (drflac_uint64 i = 0; i < frameCount; ++i) {
drflac_uint32 mid = (drflac_uint32)pInputSamples0[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
mid = (mid << 1) | (side & 0x01);
pOutputSamples[i*2+0] = (float)((((drflac_int32)(mid + side) >> 1) << (unusedBitsPerSample)) / 2147483648.0);
pOutputSamples[i*2+1] = (float)((((drflac_int32)(mid - side) >> 1) << (unusedBitsPerSample)) / 2147483648.0);
}
}
#endif
static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift = unusedBitsPerSample;
float factor = 1 / 2147483648.0;
if (shift > 0) {
shift -= 1;
for (i = 0; i < frameCount4; ++i) {
drflac_uint32 temp0L;
drflac_uint32 temp1L;
drflac_uint32 temp2L;
drflac_uint32 temp3L;
drflac_uint32 temp0R;
drflac_uint32 temp1R;
drflac_uint32 temp2R;
drflac_uint32 temp3R;
drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
mid0 = (mid0 << 1) | (side0 & 0x01);
mid1 = (mid1 << 1) | (side1 & 0x01);
mid2 = (mid2 << 1) | (side2 & 0x01);
mid3 = (mid3 << 1) | (side3 & 0x01);
temp0L = (mid0 + side0) << shift;
temp1L = (mid1 + side1) << shift;
temp2L = (mid2 + side2) << shift;
temp3L = (mid3 + side3) << shift;
temp0R = (mid0 - side0) << shift;
temp1R = (mid1 - side1) << shift;
temp2R = (mid2 - side2) << shift;
temp3R = (mid3 - side3) << shift;
pOutputSamples[i*8+0] = (drflac_int32)temp0L * factor;
pOutputSamples[i*8+1] = (drflac_int32)temp0R * factor;
pOutputSamples[i*8+2] = (drflac_int32)temp1L * factor;
pOutputSamples[i*8+3] = (drflac_int32)temp1R * factor;
pOutputSamples[i*8+4] = (drflac_int32)temp2L * factor;
pOutputSamples[i*8+5] = (drflac_int32)temp2R * factor;
pOutputSamples[i*8+6] = (drflac_int32)temp3L * factor;
pOutputSamples[i*8+7] = (drflac_int32)temp3R * factor;
}
} else {
for (i = 0; i < frameCount4; ++i) {
drflac_uint32 temp0L;
drflac_uint32 temp1L;
drflac_uint32 temp2L;
drflac_uint32 temp3L;
drflac_uint32 temp0R;
drflac_uint32 temp1R;
drflac_uint32 temp2R;
drflac_uint32 temp3R;
drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
mid0 = (mid0 << 1) | (side0 & 0x01);
mid1 = (mid1 << 1) | (side1 & 0x01);
mid2 = (mid2 << 1) | (side2 & 0x01);
mid3 = (mid3 << 1) | (side3 & 0x01);
temp0L = (drflac_uint32)((drflac_int32)(mid0 + side0) >> 1);
temp1L = (drflac_uint32)((drflac_int32)(mid1 + side1) >> 1);
temp2L = (drflac_uint32)((drflac_int32)(mid2 + side2) >> 1);
temp3L = (drflac_uint32)((drflac_int32)(mid3 + side3) >> 1);
temp0R = (drflac_uint32)((drflac_int32)(mid0 - side0) >> 1);
temp1R = (drflac_uint32)((drflac_int32)(mid1 - side1) >> 1);
temp2R = (drflac_uint32)((drflac_int32)(mid2 - side2) >> 1);
temp3R = (drflac_uint32)((drflac_int32)(mid3 - side3) >> 1);
pOutputSamples[i*8+0] = (drflac_int32)temp0L * factor;
pOutputSamples[i*8+1] = (drflac_int32)temp0R * factor;
pOutputSamples[i*8+2] = (drflac_int32)temp1L * factor;
pOutputSamples[i*8+3] = (drflac_int32)temp1R * factor;
pOutputSamples[i*8+4] = (drflac_int32)temp2L * factor;
pOutputSamples[i*8+5] = (drflac_int32)temp2R * factor;
pOutputSamples[i*8+6] = (drflac_int32)temp3L * factor;
pOutputSamples[i*8+7] = (drflac_int32)temp3R * factor;
}
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
mid = (mid << 1) | (side & 0x01);
pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample) * factor;
pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample) * factor;
}
}
#if defined(DRFLAC_SUPPORT_SSE2)
static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift = unusedBitsPerSample - 8;
float factor;
__m128 factor128;
DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
factor = 1.0f / 8388608.0f;
factor128 = _mm_set1_ps(factor);
if (shift == 0) {
for (i = 0; i < frameCount4; ++i) {
__m128i mid;
__m128i side;
__m128i tempL;
__m128i tempR;
__m128 leftf;
__m128 rightf;
mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
tempL = _mm_srai_epi32(_mm_add_epi32(mid, side), 1);
tempR = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1);
leftf = _mm_mul_ps(_mm_cvtepi32_ps(tempL), factor128);
rightf = _mm_mul_ps(_mm_cvtepi32_ps(tempR), factor128);
_mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf));
_mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
mid = (mid << 1) | (side & 0x01);
pOutputSamples[i*2+0] = ((drflac_int32)(mid + side) >> 1) * factor;
pOutputSamples[i*2+1] = ((drflac_int32)(mid - side) >> 1) * factor;
}
} else {
shift -= 1;
for (i = 0; i < frameCount4; ++i) {
__m128i mid;
__m128i side;
__m128i tempL;
__m128i tempR;
__m128 leftf;
__m128 rightf;
mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
tempL = _mm_slli_epi32(_mm_add_epi32(mid, side), shift);
tempR = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift);
leftf = _mm_mul_ps(_mm_cvtepi32_ps(tempL), factor128);
rightf = _mm_mul_ps(_mm_cvtepi32_ps(tempR), factor128);
_mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf));
_mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
mid = (mid << 1) | (side & 0x01);
pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift) * factor;
pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift) * factor;
}
}
}
#endif
#if defined(DRFLAC_SUPPORT_NEON)
static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift = unusedBitsPerSample - 8;
float factor;
float32x4_t factor4;
int32x4_t shift4;
int32x4_t wbps0_4; /* Wasted Bits Per Sample */
int32x4_t wbps1_4; /* Wasted Bits Per Sample */
DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
factor = 1.0f / 8388608.0f;
factor4 = vdupq_n_f32(factor);
wbps0_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
wbps1_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
if (shift == 0) {
for (i = 0; i < frameCount4; ++i) {
int32x4_t lefti;
int32x4_t righti;
float32x4_t leftf;
float32x4_t rightf;
uint32x4_t mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbps0_4);
uint32x4_t side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbps1_4);
mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1)));
lefti = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1);
righti = vshrq_n_s32(vreinterpretq_s32_u32(vsubq_u32(mid, side)), 1);
leftf = vmulq_f32(vcvtq_f32_s32(lefti), factor4);
rightf = vmulq_f32(vcvtq_f32_s32(righti), factor4);
drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
mid = (mid << 1) | (side & 0x01);
pOutputSamples[i*2+0] = ((drflac_int32)(mid + side) >> 1) * factor;
pOutputSamples[i*2+1] = ((drflac_int32)(mid - side) >> 1) * factor;
}
} else {
shift -= 1;
shift4 = vdupq_n_s32(shift);
for (i = 0; i < frameCount4; ++i) {
uint32x4_t mid;
uint32x4_t side;
int32x4_t lefti;
int32x4_t righti;
float32x4_t leftf;
float32x4_t rightf;
mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbps0_4);
side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbps1_4);
mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1)));
lefti = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4));
righti = vreinterpretq_s32_u32(vshlq_u32(vsubq_u32(mid, side), shift4));
leftf = vmulq_f32(vcvtq_f32_s32(lefti), factor4);
rightf = vmulq_f32(vcvtq_f32_s32(righti), factor4);
drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
mid = (mid << 1) | (side & 0x01);
pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift) * factor;
pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift) * factor;
}
}
}
#endif
static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
{
#if defined(DRFLAC_SUPPORT_SSE2)
if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
drflac_read_pcm_frames_f32__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
} else
#elif defined(DRFLAC_SUPPORT_NEON)
if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
drflac_read_pcm_frames_f32__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
} else
#endif
{
/* Scalar fallback. */
#if 0
drflac_read_pcm_frames_f32__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
#else
drflac_read_pcm_frames_f32__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
#endif
}
}
#if 0
static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOut...
{
for (drflac_uint64 i = 0; i < frameCount; ++i) {
pOutputSamples[i*2+0] = (float)((drflac_int32)((drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample)) / 2147483648.0);
pOutputSamples[i*2+1] = (float)((drflac_int32)((drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample)) / 2147483648.0);
}
}
#endif
static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutput...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
float factor = 1 / 2147483648.0;
for (i = 0; i < frameCount4; ++i) {
drflac_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0;
drflac_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0;
drflac_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0;
drflac_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0;
drflac_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1;
drflac_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1;
drflac_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1;
drflac_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1;
pOutputSamples[i*8+0] = (drflac_int32)tempL0 * factor;
pOutputSamples[i*8+1] = (drflac_int32)tempR0 * factor;
pOutputSamples[i*8+2] = (drflac_int32)tempL1 * factor;
pOutputSamples[i*8+3] = (drflac_int32)tempR1 * factor;
pOutputSamples[i*8+4] = (drflac_int32)tempL2 * factor;
pOutputSamples[i*8+5] = (drflac_int32)tempR2 * factor;
pOutputSamples[i*8+6] = (drflac_int32)tempL3 * factor;
pOutputSamples[i*8+7] = (drflac_int32)tempR3 * factor;
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor;
pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor;
}
}
#if defined(DRFLAC_SUPPORT_SSE2)
static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSa...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
float factor = 1.0f / 8388608.0f;
__m128 factor128 = _mm_set1_ps(factor);
for (i = 0; i < frameCount4; ++i) {
__m128i lefti;
__m128i righti;
__m128 leftf;
__m128 rightf;
lefti = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
righti = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
leftf = _mm_mul_ps(_mm_cvtepi32_ps(lefti), factor128);
rightf = _mm_mul_ps(_mm_cvtepi32_ps(righti), factor128);
_mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf));
_mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor;
pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor;
}
}
#endif
#if defined(DRFLAC_SUPPORT_NEON)
static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSa...
{
drflac_uint64 i;
drflac_uint64 frameCount4 = frameCount >> 2;
const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
float factor = 1.0f / 8388608.0f;
float32x4_t factor4 = vdupq_n_f32(factor);
int32x4_t shift0_4 = vdupq_n_s32(shift0);
int32x4_t shift1_4 = vdupq_n_s32(shift1);
for (i = 0; i < frameCount4; ++i) {
int32x4_t lefti;
int32x4_t righti;
float32x4_t leftf;
float32x4_t rightf;
lefti = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4));
righti = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4));
leftf = vmulq_f32(vcvtq_f32_s32(lefti), factor4);
rightf = vmulq_f32(vcvtq_f32_s32(righti), factor4);
drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf));
}
for (i = (frameCount4 << 2); i < frameCount; ++i) {
pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor;
pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor;
}
}
#endif
static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
{
#if defined(DRFLAC_SUPPORT_SSE2)
if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
drflac_read_pcm_frames_f32__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
} else
#elif defined(DRFLAC_SUPPORT_NEON)
if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
drflac_read_pcm_frames_f32__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
} else
#endif
{
/* Scalar fallback. */
#if 0
drflac_read_pcm_frames_f32__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
#else
drflac_read_pcm_frames_f32__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
#endif
}
}
DRFLAC_API drflac_uint64 drflac_read_pcm_frames_f32(drflac* pFlac, drflac_uint64 framesToRead, float* pBufferOut)
{
drflac_uint64 framesRead;
drflac_uint32 unusedBitsPerSample;
if (pFlac == NULL || framesToRead == 0) {
return 0;
}
if (pBufferOut == NULL) {
return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead);
}
DRFLAC_ASSERT(pFlac->bitsPerSample <= 32);
unusedBitsPerSample = 32 - pFlac->bitsPerSample;
framesRead = 0;
while (framesToRead > 0) {
/* If we've run out of samples in this frame, go to the next. */
if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
if (!drflac__read_and_decode_next_flac_frame(pFlac)) {
break; /* Couldn't read the next frame, so just break from the loop and return. */
}
} else {
unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment);
drflac_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining;
drflac_uint64 frameCountThisIteration = framesToRead;
if (frameCountThisIteration > pFlac->currentFLACFrame.pcmFramesRemaining) {
frameCountThisIteration = pFlac->currentFLACFrame.pcmFramesRemaining;
}
if (channelCount == 2) {
const drflac_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame;
const drflac_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame;
switch (pFlac->currentFLACFrame.header.channelAssignment)
{
case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE:
{
drflac_read_pcm_frames_f32__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
} break;
case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE:
{
drflac_read_pcm_frames_f32__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
} break;
case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE:
{
drflac_read_pcm_frames_f32__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
} break;
case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT:
default:
{
drflac_read_pcm_frames_f32__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
} break;
}
} else {
/* Generic interleaving. */
drflac_uint64 i;
for (i = 0; i < frameCountThisIteration; ++i) {
unsigned int j;
for (j = 0; j < channelCount; ++j) {
drflac_int32 sampleS32 = (drflac_int32)((drflac_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample));
pBufferOut[(i*channelCount)+j] = (float)(sampleS32 / 2147483648.0);
}
}
}
framesRead += frameCountThisIteration;
pBufferOut += frameCountThisIteration * channelCount;
framesToRead -= frameCountThisIteration;
pFlac->currentPCMFrame += frameCountThisIteration;
pFlac->currentFLACFrame.pcmFramesRemaining -= (unsigned int)frameCountThisIteration;
}
}
return framesRead;
}
DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex)
{
if (pFlac == NULL) {
return DRFLAC_FALSE;
}
/* Don't do anything if we're already on the seek point. */
if (pFlac->currentPCMFrame == pcmFrameIndex) {
return DRFLAC_TRUE;
}
/*
If we don't know where the first frame begins then we can't seek. This will happen when the STREAMINFO block was not present
when the decoder was opened.
*/
if (pFlac->firstFLACFramePosInBytes == 0) {
return DRFLAC_FALSE;
}
if (pcmFrameIndex == 0) {
pFlac->currentPCMFrame = 0;
return drflac__seek_to_first_frame(pFlac);
} else {
drflac_bool32 wasSuccessful = DRFLAC_FALSE;
/* Clamp the sample to the end. */
if (pcmFrameIndex > pFlac->totalPCMFrameCount) {
pcmFrameIndex = pFlac->totalPCMFrameCount;
}
/* If the target sample and the current sample are in the same frame we just move the position forward. */
if (pcmFrameIndex > pFlac->currentPCMFrame) {
/* Forward. */
drflac_uint32 offset = (drflac_uint32)(pcmFrameIndex - pFlac->currentPCMFrame);
if (pFlac->currentFLACFrame.pcmFramesRemaining > offset) {
pFlac->currentFLACFrame.pcmFramesRemaining -= offset;
pFlac->currentPCMFrame = pcmFrameIndex;
return DRFLAC_TRUE;
}
} else {
/* Backward. */
drflac_uint32 offsetAbs = (drflac_uint32)(pFlac->currentPCMFrame - pcmFrameIndex);
drflac_uint32 currentFLACFramePCMFrameCount = pFlac->currentFLACFrame.header.blockSizeInPCMFrames;
drflac_uint32 currentFLACFramePCMFramesConsumed = currentFLACFramePCMFrameCount - pFlac->currentFLACFrame.pcmFramesRemaining;
if (currentFLACFramePCMFramesConsumed > offsetAbs) {
pFlac->currentFLACFrame.pcmFramesRemaining += offsetAbs;
pFlac->currentPCMFrame = pcmFrameIndex;
return DRFLAC_TRUE;
}
}
/*
Different techniques depending on encapsulation. Using the native FLAC seektable with Ogg encapsulation is a bit awkward so
we'll instead use Ogg's natural seeking facility.
*/
#ifndef DR_FLAC_NO_OGG
if (pFlac->container == drflac_container_ogg)
{
wasSuccessful = drflac_ogg__seek_to_pcm_frame(pFlac, pcmFrameIndex);
}
else
#endif
{
/* First try seeking via the seek table. If this fails, fall back to a brute force seek which is much slower. */
if (/*!wasSuccessful && */!pFlac->_noSeekTableSeek) {
wasSuccessful = drflac__seek_to_pcm_frame__seek_table(pFlac, pcmFrameIndex);
}
#if !defined(DR_FLAC_NO_CRC)
/* Fall back to binary search if seek table seeking fails. This requires the length of the stream to be known. */
if (!wasSuccessful && !pFlac->_noBinarySearchSeek && pFlac->totalPCMFrameCount > 0) {
wasSuccessful = drflac__seek_to_pcm_frame__binary_search(pFlac, pcmFrameIndex);
}
#endif
/* Fall back to brute force if all else fails. */
if (!wasSuccessful && !pFlac->_noBruteForceSeek) {
wasSuccessful = drflac__seek_to_pcm_frame__brute_force(pFlac, pcmFrameIndex);
}
}
pFlac->currentPCMFrame = pcmFrameIndex;
return wasSuccessful;
}
}
/* High Level APIs */
#if defined(SIZE_MAX)
#define DRFLAC_SIZE_MAX SIZE_MAX
#else
#if defined(DRFLAC_64BIT)
#define DRFLAC_SIZE_MAX ((drflac_uint64)0xFFFFFFFFFFFFFFFF)
#else
#define DRFLAC_SIZE_MAX 0xFFFFFFFF
#endif
#endif
/* Using a macro as the definition of the drflac__full_decode_and_close_*() API family. Sue me. */
#define DRFLAC_DEFINE_FULL_READ_AND_CLOSE(extension, type) \
static type* drflac__full_read_and_close_ ## extension (drflac* pFlac, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut)\
{ \
type* pSampleData = NULL; \
drflac_uint64 totalPCMFrameCount; \
\
DRFLAC_ASSERT(pFlac != NULL); \
\
totalPCMFrameCount = pFlac->totalPCMFrameCount; \
\
if (totalPCMFrameCount == 0) { \
type buffer[4096]; \
drflac_uint64 pcmFramesRead; \
size_t sampleDataBufferSize = sizeof(buffer); \
\
pSampleData = (type*)drflac__malloc_from_callbacks(sampleDataBufferSize, &pFlac->allocationCallbacks); \
if (pSampleData == NULL) { \
goto on_error; \
} \
\
while ((pcmFramesRead = (drflac_uint64)drflac_read_pcm_frames_##extension(pFlac, sizeof(buffer)/sizeof(buffer[0])/pFlac->channels, buffer)) > 0) { \
if (((totalPCMFrameCount + pcmFramesRead) * pFlac->channels * sizeof(type)) > sampleDataBufferSize) { \
type* pNewSampleData; \
size_t newSampleDataBufferSize; \
\
newSampleDataBufferSize = sampleDataBufferSize * 2; \
pNewSampleData = (type*)drflac__realloc_from_callbacks(pSampleData, newSampleDataBufferSize, sampleDataBufferSize, &pFlac->allocationCallbacks); \
if (pNewSampleData == NULL) { \
drflac__free_from_callbacks(pSampleData, &pFlac->allocationCallbacks); \
goto on_error; \
} \
\
sampleDataBufferSize = newSampleDataBufferSize; \
pSampleData = pNewSampleData; \
} \
\
DRFLAC_COPY_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), buffer, (size_t)(pcmFramesRead*pFlac->channels*sizeof(type))); \
totalPCMFrameCount += pcmFramesRead; \
} \
\
/* At this point everything should be decoded, but we just want to fill the unused part buffer with silence - need to \
protect those ears from random noise! */ \
DRFLAC_ZERO_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), (size_t)(sampleDataBufferSize - totalPCMFrameCount*pFlac->channels*sizeof(type))); \
} else { \
drflac_uint64 dataSize = totalPCMFrameCount*pFlac->channels*sizeof(type); \
if (dataSize > DRFLAC_SIZE_MAX) { \
goto on_error; /* The decoded data is too big. */ \
} \
\
pSampleData = (type*)drflac__malloc_from_callbacks((size_t)dataSize, &pFlac->allocationCallbacks); /* <-- Safe cast as per the check above. */ \
if (pSampleData == NULL) { \
goto on_error; \
} \
\
totalPCMFrameCount = drflac_read_pcm_frames_##extension(pFlac, pFlac->totalPCMFrameCount, pSampleData); \
} \
\
if (sampleRateOut) *sampleRateOut = pFlac->sampleRate; \
if (channelsOut) *channelsOut = pFlac->channels; \
if (totalPCMFrameCountOut) *totalPCMFrameCountOut = totalPCMFrameCount; \
\
drflac_close(pFlac); \
return pSampleData; \
\
on_error: \
drflac_close(pFlac); \
return NULL; \
}
DRFLAC_DEFINE_FULL_READ_AND_CLOSE(s32, drflac_int32)
DRFLAC_DEFINE_FULL_READ_AND_CLOSE(s16, drflac_int16)
DRFLAC_DEFINE_FULL_READ_AND_CLOSE(f32, float)
DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_call...
{
drflac* pFlac;
if (channelsOut) {
*channelsOut = 0;
}
if (sampleRateOut) {
*sampleRateOut = 0;
}
if (totalPCMFrameCountOut) {
*totalPCMFrameCountOut = 0;
}
pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
return drflac__full_read_and_close_s32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
}
DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_call...
{
drflac* pFlac;
if (channelsOut) {
*channelsOut = 0;
}
if (sampleRateOut) {
*sampleRateOut = 0;
}
if (totalPCMFrameCountOut) {
*totalPCMFrameCountOut = 0;
}
pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
return drflac__full_read_and_close_s16(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
}
DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* ...
{
drflac* pFlac;
if (channelsOut) {
*channelsOut = 0;
}
if (sampleRateOut) {
*sampleRateOut = 0;
}
if (totalPCMFrameCountOut) {
*totalPCMFrameCountOut = 0;
}
pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
return drflac__full_read_and_close_f32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
}
#ifndef DR_FLAC_NO_STDIO
DRFLAC_API drflac_int32* drflac_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac* pFlac;
if (sampleRate) {
*sampleRate = 0;
}
if (channels) {
*channels = 0;
}
if (totalPCMFrameCount) {
*totalPCMFrameCount = 0;
}
pFlac = drflac_open_file(filename, pAllocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
return drflac__full_read_and_close_s32(pFlac, channels, sampleRate, totalPCMFrameCount);
}
DRFLAC_API drflac_int16* drflac_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac* pFlac;
if (sampleRate) {
*sampleRate = 0;
}
if (channels) {
*channels = 0;
}
if (totalPCMFrameCount) {
*totalPCMFrameCount = 0;
}
pFlac = drflac_open_file(filename, pAllocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
return drflac__full_read_and_close_s16(pFlac, channels, sampleRate, totalPCMFrameCount);
}
DRFLAC_API float* drflac_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac* pFlac;
if (sampleRate) {
*sampleRate = 0;
}
if (channels) {
*channels = 0;
}
if (totalPCMFrameCount) {
*totalPCMFrameCount = 0;
}
pFlac = drflac_open_file(filename, pAllocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
return drflac__full_read_and_close_f32(pFlac, channels, sampleRate, totalPCMFrameCount);
}
#endif
DRFLAC_API drflac_int32* drflac_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac* pFlac;
if (sampleRate) {
*sampleRate = 0;
}
if (channels) {
*channels = 0;
}
if (totalPCMFrameCount) {
*totalPCMFrameCount = 0;
}
pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
return drflac__full_read_and_close_s32(pFlac, channels, sampleRate, totalPCMFrameCount);
}
DRFLAC_API drflac_int16* drflac_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac* pFlac;
if (sampleRate) {
*sampleRate = 0;
}
if (channels) {
*channels = 0;
}
if (totalPCMFrameCount) {
*totalPCMFrameCount = 0;
}
pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
return drflac__full_read_and_close_s16(pFlac, channels, sampleRate, totalPCMFrameCount);
}
DRFLAC_API float* drflac_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
{
drflac* pFlac;
if (sampleRate) {
*sampleRate = 0;
}
if (channels) {
*channels = 0;
}
if (totalPCMFrameCount) {
*totalPCMFrameCount = 0;
}
pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks);
if (pFlac == NULL) {
return NULL;
}
return drflac__full_read_and_close_f32(pFlac, channels, sampleRate, totalPCMFrameCount);
}
DRFLAC_API void drflac_free(void* p, const drflac_allocation_callbacks* pAllocationCallbacks)
{
if (pAllocationCallbacks != NULL) {
drflac__free_from_callbacks(p, pAllocationCallbacks);
} else {
drflac__free_default(p, NULL);
}
}
DRFLAC_API void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const void* pComments)
{
if (pIter == NULL) {
return;
}
pIter->countRemaining = commentCount;
pIter->pRunningData = (const char*)pComments;
}
DRFLAC_API const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut)
{
drflac_int32 length;
const char* pComment;
/* Safety. */
if (pCommentLengthOut) {
*pCommentLengthOut = 0;
}
if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) {
return NULL;
}
length = drflac__le2host_32(*(const drflac_uint32*)pIter->pRunningData);
pIter->pRunningData += 4;
share/public_html/static/music_inc/src/dr_flac.h view on Meta::CPAN
- DRFLAC_VERSION_STRING
- drflac_version()
- drflac_version_string()
v0.12.12 - 2020-04-30
- Fix compilation errors with VC6.
v0.12.11 - 2020-04-19
- Fix some pedantic warnings.
- Fix some undefined behaviour warnings.
v0.12.10 - 2020-04-10
- Fix some bugs when trying to seek with an invalid seek table.
v0.12.9 - 2020-04-05
- Fix warnings.
v0.12.8 - 2020-04-04
- Add drflac_open_file_w() and drflac_open_file_with_metadata_w().
- Fix some static analysis warnings.
- Minor documentation updates.
v0.12.7 - 2020-03-14
- Fix compilation errors with VC6.
v0.12.6 - 2020-03-07
- Fix compilation error with Visual Studio .NET 2003.
v0.12.5 - 2020-01-30
- Silence some static analysis warnings.
v0.12.4 - 2020-01-29
- Silence some static analysis warnings.
v0.12.3 - 2019-12-02
- Fix some warnings when compiling with GCC and the -Og flag.
- Fix a crash in out-of-memory situations.
- Fix potential integer overflow bug.
- Fix some static analysis warnings.
- Fix a possible crash when using custom memory allocators without a custom realloc() implementation.
- Fix a bug with binary search seeking where the bits per sample is not a multiple of 8.
v0.12.2 - 2019-10-07
- Internal code clean up.
v0.12.1 - 2019-09-29
- Fix some Clang Static Analyzer warnings.
- Fix an unused variable warning.
v0.12.0 - 2019-09-23
- API CHANGE: Add support for user defined memory allocation routines. This system allows the program to specify their own memory allocation
routines with a user data pointer for client-specific contextual data. This adds an extra parameter to the end of the following APIs:
- drflac_open()
- drflac_open_relaxed()
- drflac_open_with_metadata()
- drflac_open_with_metadata_relaxed()
- drflac_open_file()
- drflac_open_file_with_metadata()
- drflac_open_memory()
- drflac_open_memory_with_metadata()
- drflac_open_and_read_pcm_frames_s32()
- drflac_open_and_read_pcm_frames_s16()
- drflac_open_and_read_pcm_frames_f32()
- drflac_open_file_and_read_pcm_frames_s32()
- drflac_open_file_and_read_pcm_frames_s16()
- drflac_open_file_and_read_pcm_frames_f32()
- drflac_open_memory_and_read_pcm_frames_s32()
- drflac_open_memory_and_read_pcm_frames_s16()
- drflac_open_memory_and_read_pcm_frames_f32()
Set this extra parameter to NULL to use defaults which is the same as the previous behaviour. Setting this NULL will use
DRFLAC_MALLOC, DRFLAC_REALLOC and DRFLAC_FREE.
- Remove deprecated APIs:
- drflac_read_s32()
- drflac_read_s16()
- drflac_read_f32()
- drflac_seek_to_sample()
- drflac_open_and_decode_s32()
- drflac_open_and_decode_s16()
- drflac_open_and_decode_f32()
- drflac_open_and_decode_file_s32()
- drflac_open_and_decode_file_s16()
- drflac_open_and_decode_file_f32()
- drflac_open_and_decode_memory_s32()
- drflac_open_and_decode_memory_s16()
- drflac_open_and_decode_memory_f32()
- Remove drflac.totalSampleCount which is now replaced with drflac.totalPCMFrameCount. You can emulate drflac.totalSampleCount
by doing pFlac->totalPCMFrameCount*pFlac->channels.
- Rename drflac.currentFrame to drflac.currentFLACFrame to remove ambiguity with PCM frames.
- Fix errors when seeking to the end of a stream.
- Optimizations to seeking.
- SSE improvements and optimizations.
- ARM NEON optimizations.
- Optimizations to drflac_read_pcm_frames_s16().
- Optimizations to drflac_read_pcm_frames_s32().
v0.11.10 - 2019-06-26
- Fix a compiler error.
v0.11.9 - 2019-06-16
- Silence some ThreadSanitizer warnings.
v0.11.8 - 2019-05-21
- Fix warnings.
v0.11.7 - 2019-05-06
- C89 fixes.
v0.11.6 - 2019-05-05
- Add support for C89.
- Fix a compiler warning when CRC is disabled.
- Change license to choice of public domain or MIT-0.
v0.11.5 - 2019-04-19
- Fix a compiler error with GCC.
v0.11.4 - 2019-04-17
- Fix some warnings with GCC when compiling with -std=c99.
v0.11.3 - 2019-04-07
- Silence warnings with GCC.
v0.11.2 - 2019-03-10
- Fix a warning.
v0.11.1 - 2019-02-17
- Fix a potential bug with seeking.
v0.11.0 - 2018-12-16
- API CHANGE: Deprecated drflac_read_s32(), drflac_read_s16() and drflac_read_f32() and replaced them with
drflac_read_pcm_frames_s32(), drflac_read_pcm_frames_s16() and drflac_read_pcm_frames_f32(). The new APIs take
and return PCM frame counts instead of sample counts. To upgrade you will need to change the input count by
dividing it by the channel count, and then do the same with the return value.
- API_CHANGE: Deprecated drflac_seek_to_sample() and replaced with drflac_seek_to_pcm_frame(). Same rules as
the changes to drflac_read_*() apply.
- API CHANGE: Deprecated drflac_open_and_decode_*() and replaced with drflac_open_*_and_read_*(). Same rules as
the changes to drflac_read_*() apply.
- Optimizations.
v0.10.0 - 2018-09-11
- Remove the DR_FLAC_NO_WIN32_IO option and the Win32 file IO functionality. If you need to use Win32 file IO you
need to do it yourself via the callback API.
- Fix the clang build.
- Fix undefined behavior.
- Fix errors with CUESHEET metdata blocks.
- Add an API for iterating over each cuesheet track in the CUESHEET metadata block. This works the same way as the
Vorbis comment API.
- Other miscellaneous bug fixes, mostly relating to invalid FLAC streams.
- Minor optimizations.
v0.9.11 - 2018-08-29
- Fix a bug with sample reconstruction.
v0.9.10 - 2018-08-07
- Improve 64-bit detection.
v0.9.9 - 2018-08-05
- Fix C++ build on older versions of GCC.
v0.9.8 - 2018-07-24
- Fix compilation errors.
v0.9.7 - 2018-07-05
- Fix a warning.
v0.9.6 - 2018-06-29
- Fix some typos.
v0.9.5 - 2018-06-23
- Fix some warnings.
v0.9.4 - 2018-06-14
- Optimizations to seeking.
- Clean up.
v0.9.3 - 2018-05-22
- Bug fix.
v0.9.2 - 2018-05-12
- Fix a compilation error due to a missing break statement.
v0.9.1 - 2018-04-29
- Fix compilation error with Clang.
v0.9 - 2018-04-24
- Fix Clang build.
- Start using major.minor.revision versioning.
v0.8g - 2018-04-19
- Fix build on non-x86/x64 architectures.
v0.8f - 2018-02-02
- Stop pretending to support changing rate/channels mid stream.
v0.8e - 2018-02-01
- Fix a crash when the block size of a frame is larger than the maximum block size defined by the FLAC stream.
- Fix a crash the the Rice partition order is invalid.
v0.8d - 2017-09-22
- Add support for decoding streams with ID3 tags. ID3 tags are just skipped.
v0.8c - 2017-09-07
- Fix warning on non-x86/x64 architectures.
v0.8b - 2017-08-19
- Fix build on non-x86/x64 architectures.
v0.8a - 2017-08-13
- A small optimization for the Clang build.
v0.8 - 2017-08-12
- API CHANGE: Rename dr_* types to drflac_*.
- Optimizations. This brings dr_flac back to about the same class of efficiency as the reference implementation.
- Add support for custom implementations of malloc(), realloc(), etc.
- Add CRC checking to Ogg encapsulated streams.
- Fix VC++ 6 build. This is only for the C++ compiler. The C compiler is not currently supported.
- Bug fixes.
v0.7 - 2017-07-23
- Add support for opening a stream without a header block. To do this, use drflac_open_relaxed() / drflac_open_with_metadata_relaxed().
v0.6 - 2017-07-22
- Add support for recovering from invalid frames. With this change, dr_flac will simply skip over invalid frames as if they
never existed. Frames are checked against their sync code, the CRC-8 of the frame header and the CRC-16 of the whole frame.
v0.5 - 2017-07-16
- Fix typos.
- Change drflac_bool* types to unsigned.
- Add CRC checking. This makes dr_flac slower, but can be disabled with #define DR_FLAC_NO_CRC.
v0.4f - 2017-03-10
- Fix a couple of bugs with the bitstreaming code.
v0.4e - 2017-02-17
- Fix some warnings.
v0.4d - 2016-12-26
- Add support for 32-bit floating-point PCM decoding.
- Use drflac_int* and drflac_uint* sized types to improve compiler support.
- Minor improvements to documentation.
v0.4c - 2016-12-26
- Add support for signed 16-bit integer PCM decoding.
v0.4b - 2016-10-23
- A minor change to drflac_bool8 and drflac_bool32 types.
v0.4a - 2016-10-11
- Rename drBool32 to drflac_bool32 for styling consistency.
v0.4 - 2016-09-29
- API/ABI CHANGE: Use fixed size 32-bit booleans instead of the built-in bool type.
- API CHANGE: Rename drflac_open_and_decode*() to drflac_open_and_decode*_s32().
- API CHANGE: Swap the order of "channels" and "sampleRate" parameters in drflac_open_and_decode*(). Rationale for this is to
keep it consistent with drflac_audio.
v0.3f - 2016-09-21
- Fix a warning with GCC.
v0.3e - 2016-09-18
- Fixed a bug where GCC 4.3+ was not getting properly identified.
- Fixed a few typos.
- Changed date formats to ISO 8601 (YYYY-MM-DD).
v0.3d - 2016-06-11
- Minor clean up.
v0.3c - 2016-05-28
- Fixed compilation error.
v0.3b - 2016-05-16
- Fixed Linux/GCC build.
- Updated documentation.
v0.3a - 2016-05-15
- Minor fixes to documentation.
v0.3 - 2016-05-11
- Optimizations. Now at about parity with the reference implementation on 32-bit builds.
- Lots of clean up.
v0.2b - 2016-05-10
- Bug fixes.