diff --git a/extras/dr_flac.h b/extras/dr_flac.h index ccbcccb1..53932623 100644 --- a/extras/dr_flac.h +++ b/extras/dr_flac.h @@ -1,112 +1,118 @@ -// FLAC audio decoder. Public domain. See "unlicense" statement at the end of this file. -// dr_flac - v0.11.5 - 2018-04-19 -// -// David Reid - mackron@gmail.com +/* +FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file. +dr_flac - v0.11.6 - 2019-05-05 -// USAGE -// -// dr_flac is a single-file library. To use it, do something like the following in one .c file. -// #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: -// -// drflac* pFlac = drflac_open_file("MySong.flac"); -// 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: -// -// while (drflac_read_pcm_frames_s32(pFlac, chunkSizeInPCMFrames, pChunkSamples) > 0) { -// do_something(); -// } -// -// You can seek to a specific sample with drflac_seek_to_sample(). The given sample is based on interleaving. So for example, -// if you were to seek to the sample at index 0 in a stereo stream, you'll be seeking to the first sample of the left channel. -// The sample at index 1 will be the first sample of the right channel. The sample at index 2 will be the second sample of the -// left channel, etc. -// -// -// If you just want to quickly decode an entire FLAC file in one go you can do something like this: -// -// 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); -// 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 like 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() and 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 -// corrupted 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. -// -// -// -// 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 -// 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. -// -// #define DR_FLAC_NO_SIMD -// Disables SIMD optimizations (SSE on x86/x64 architectures). Use this if you are having compatibility issues with your -// compiler. -// -// -// -// QUICK NOTES -// - dr_flac does not currently support changing the sample rate nor channel count mid stream. -// - Audio data is output as signed 32-bit PCM, regardless of the bits per sample the FLAC stream is encoded as. -// - This has not been tested on big-endian architectures. -// - 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. +David Reid - mackron@gmail.com +*/ + +/* +USAGE +===== +dr_flac is a single-file library. To use it, do something like the following in one .c file. + #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: + + drflac* pFlac = drflac_open_file("MySong.flac"); + 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: + + while (drflac_read_pcm_frames_s32(pFlac, chunkSizeInPCMFrames, pChunkSamples) > 0) { + do_something(); + } + +You can seek to a specific sample with drflac_seek_to_sample(). The given sample is based on interleaving. So for example, +if you were to seek to the sample at index 0 in a stereo stream, you'll be seeking to the first sample of the left channel. +The sample at index 1 will be the first sample of the right channel. The sample at index 2 will be the second sample of the +left channel, etc. + + +If you just want to quickly decode an entire FLAC file in one go you can do something like this: + + 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); + 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 like 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() and 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 +corrupted 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. + + + +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 + 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. + +#define DR_FLAC_NO_SIMD + Disables SIMD optimizations (SSE on x86/x64 architectures). Use this if you are having compatibility issues with your + compiler. + + + +QUICK NOTES +=========== +- dr_flac does not currently support changing the sample rate nor channel count mid stream. +- Audio data is output as signed 32-bit PCM, regardless of the bits per sample the FLAC stream is encoded as. +- This has not been tested on big-endian architectures. +- 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. +*/ #ifndef dr_flac_h #define dr_flac_h @@ -152,9 +158,11 @@ typedef drflac_uint32 drflac_bool32; #define DRFLAC_DEPRECATED #endif -// As data is read from the client it is placed into an internal buffer for fast access. This controls the -// size of that buffer. Larger values means more speed, but also more memory. In my testing there is diminishing -// returns after about 4KB, but you can fiddle with this to suit your own needs. Must be a multiple of 8. +/* +As data is read from the client it is placed into an internal buffer for fast access. This controls the +size of that buffer. Larger values means more speed, but also more memory. In my testing there is diminishing +returns after about 4KB, but you can fiddle with this to suit your own needs. Must be a multiple of 8. +*/ #ifndef DR_FLAC_BUFFER_SIZE #define DR_FLAC_BUFFER_SIZE 4096 #endif @@ -163,7 +171,7 @@ typedef drflac_uint32 drflac_bool32; extern "C" { #endif -// Check if we can enable 64-bit optimizations. +/* Check if we can enable 64-bit optimizations. */ #if defined(_WIN64) || defined(_LP64) || defined(__LP64__) #define DRFLAC_64BIT #endif @@ -174,7 +182,7 @@ typedef drflac_uint64 drflac_cache_t; typedef drflac_uint32 drflac_cache_t; #endif -// The various metadata block types. +/* 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 @@ -184,7 +192,7 @@ typedef drflac_uint32 drflac_cache_t; #define DRFLAC_METADATA_BLOCK_TYPE_PICTURE 6 #define DRFLAC_METADATA_BLOCK_TYPE_INVALID 127 -// The various picture types specified in the PICTURE block. +/* 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 @@ -220,12 +228,12 @@ typedef enum 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. +/* 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 firstSample; - drflac_uint64 frameOffset; // The offset from the first byte of the header of the first frame. + drflac_uint64 frameOffset; /* The offset from the first byte of the header of the first frame. */ drflac_uint16 sampleCount; } drflac_seekpoint; #pragma pack() @@ -245,15 +253,17 @@ typedef struct typedef struct { - // The metadata type. Use this to know how to interpret the data below. + /* 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. + /* + 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. + /* The size in bytes of the block and the buffer pointed to by pRawData if it's non-NULL. */ drflac_uint32 rawDataSize; union @@ -313,40 +323,46 @@ typedef struct } drflac_metadata; -// Callback for when data needs to be read from the client. -// -// 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. -// -// Returns the number of bytes actually read. -// -// 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. +/* +Callback for when data needs to be read from the client. + +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. + +Returns the number of bytes actually read. + +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. -// -// 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. -// -// Returns whether or not the seek was successful. -// -// 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. +/* +Callback for when data needs to be seeked. + +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. + +Returns whether or not the seek was successful. + +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. +*/ typedef drflac_bool32 (* drflac_seek_proc)(void* pUserData, int offset, drflac_seek_origin origin); -// Callback for when a metadata block is read. -// -// 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. -// -// Use pMetadata->type to determine which metadata block is being handled and how to read the data. +/* +Callback for when a metadata block is read. + +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. + +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); -// Structure for internal use. Only used for decoders opened with drflac_open_memory. +/* Structure for internal use. Only used for decoders opened with drflac_open_memory. */ typedef struct { const drflac_uint8* data; @@ -354,379 +370,431 @@ typedef struct size_t currentReadPos; } drflac__memory_stream; -// Structure for internal use. Used for bit streaming. +/* Structure for internal use. Used for bit streaming. */ typedef struct { - // The function to call when more data needs to be read. + /* 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. + /* 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. + /* 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). + /* + 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. + /* The content of the unaligned bytes. */ drflac_cache_t unalignedCache; - // The index of the next valid cache line in the "L2" cache. + /* 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. + /* 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. + /* + 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. + /* + 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_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. + /* 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. + /* 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. + /* The order to use for the prediction stage for SUBFRAME_FIXED and SUBFRAME_LPC. */ drflac_uint8 lpcOrder; - // The number of bits per sample for this subframe. This is not always equal to the current frame's bit per sample because - // an extra bit is required for side channels when interchannel decorrelation is being used. + /* + The number of bits per sample for this subframe. This is not always equal to the current frame's bit per sample because + an extra bit is required for side channels when interchannel decorrelation is being used. + */ drflac_uint32 bitsPerSample; - // A pointer to the buffer containing the decoded samples in the subframe. This pointer is an offset from drflac::pExtraData. Note that - // it's a signed 32-bit integer for each value. + /* + A pointer to the buffer containing the decoded samples in the subframe. This pointer is an offset from drflac::pExtraData. Note that + it's a signed 32-bit integer for each value. + */ drflac_int32* pDecodedSamples; } drflac_subframe; typedef struct { - // If the stream uses variable block sizes, this will be set to the index of the first sample. If fixed block sizes are used, this will - // always be set to 0. + /* + If the stream uses variable block sizes, this will be set to the index of the first sample. If fixed block sizes are used, this will + always be set to 0. + */ drflac_uint64 sampleNumber; - // 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. + /* 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. */ drflac_uint32 frameNumber; - // The sample rate of this frame. + /* The sample rate of this frame. */ drflac_uint32 sampleRate; - // The number of samples in each sub-frame within this frame. + /* The number of samples in each sub-frame within this frame. */ drflac_uint16 blockSize; - // 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. + /* + 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. + /* The number of bits per sample within this frame. */ drflac_uint8 bitsPerSample; - // The frame's CRC. + /* The frame's CRC. */ drflac_uint8 crc8; } drflac_frame_header; typedef struct { - // The header. + /* The header. */ drflac_frame_header header; - // The number of samples left to be read in this frame. This is initially set to the block size multiplied by the channel count. As samples - // are read, this will be decremented. When it reaches 0, the decoder will see this frame as fully consumed and load the next frame. + /* + The number of samples left to be read in this frame. This is initially set to the block size multiplied by the channel count. As samples + 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 samplesRemaining; - // The list of sub-frames within the frame. There is one sub-frame for each channel, and there's a maximum of 8 channels. + /* 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. + /* The function to call when a metadata block is read. */ drflac_meta_proc onMeta; - // The user data posted to the metadata callback function. + /* The user data posted to the metadata callback function. */ void* pUserDataMD; - // The sample rate. Will be set to something like 44100. + /* 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. + /* + 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. + /* 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). + /* The maximum block size, in samples. This number represents the number of samples in each channel (not combined). */ drflac_uint16 maxBlockSize; - // The total number of samples making up the stream. This includes every channel. For example, if the stream has 2 channels, - // with each channel having a total of 4096, this value will be set to 2*4096 = 8192. Can be 0 in which case it's still a - // valid stream, but just means the total sample count is unknown. Likely the case with streams like internet radio. + /* + The total number of samples making up the stream. This includes every channel. For example, if the stream has 2 channels, + with each channel having a total of 4096, this value will be set to 2*4096 = 8192. Can be 0 in which case it's still a + valid stream, but just means the total sample count is unknown. Likely the case with streams like internet radio. + */ drflac_uint64 totalSampleCount; - drflac_uint64 totalPCMFrameCount; // <-- Equal to totalSampleCount / channels. + drflac_uint64 totalPCMFrameCount; /* <-- Equal to totalSampleCount / channels. */ - // The container type. This is set based on whether or not the decoder was opened from a native or Ogg stream. + /* 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. + /* The number of seekpoints in the seektable. */ drflac_uint32 seekpointCount; - // Information about the frame the decoder is currently sitting on. + /* Information about the frame the decoder is currently sitting on. */ drflac_frame currentFrame; - // The index of the sample the decoder is currently sitting on. This is only used for seeking. + /* The index of the sample the decoder is currently sitting on. This is only used for seeking. */ drflac_uint64 currentSample; - // The position of the first frame in the stream. This is only ever used for seeking. + /* The position of the first frame in the stream. This is only ever used for seeking. */ drflac_uint64 firstFramePos; - // A hack to avoid a malloc() when opening a decoder with drflac_open_memory(). + /* 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. + /* 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. + /* 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. + /* Internal use only. Only used with Ogg containers. Points to a drflac_oggbs object. This is an offset of pExtraData. */ void* _oggbs; - // The bit streamer. The raw FLAC data is fed through this object. + /* 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. + /* 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. -// -// 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. -// -// Returns a pointer to an object representing the decoder. -// -// Close the decoder with drflac_close(). -// -// 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. -// -// See also: drflac_open_file(), drflac_open_memory(), drflac_open_with_metadata(), drflac_close() +/* +Opens a FLAC decoder. + +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. + +Returns a pointer to an object representing the decoder. + +Close the decoder with drflac_close(). + +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. + +See also: drflac_open_file(), drflac_open_memory(), drflac_open_with_metadata(), drflac_close() +*/ drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData); -// 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 - 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. +/* +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 - 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* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData); -// Opens a FLAC decoder and notifies the caller of the metadata chunks (album art, etc.). -// -// 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. -// -// Returns a pointer to an object representing the decoder. -// -// Close the decoder with drflac_close(). -// -// This is slower than drflac_open(), so avoid this one if you don't need metadata. Internally, this will do a DRFLAC_MALLOC() -// and DRFLAC_FREE() 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. -// -// See also: drflac_open_file_with_metadata(), drflac_open_memory_with_metadata(), drflac_open(), drflac_close() +/* +Opens a FLAC decoder and notifies the caller of the metadata chunks (album art, etc.). + +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. + +Returns a pointer to an object representing the decoder. + +Close the decoder with drflac_close(). + +This is slower than drflac_open(), so avoid this one if you don't need metadata. Internally, this will do a DRFLAC_MALLOC() +and DRFLAC_FREE() 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. + +See also: drflac_open_file_with_metadata(), drflac_open_memory_with_metadata(), drflac_open(), drflac_close() +*/ drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData); -// 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() +/* +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* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData); -// Closes the given FLAC decoder. -// -// pFlac [in] The decoder to close. -// -// This will destroy the decoder object. +/* +Closes the given FLAC decoder. + +pFlac [in] The decoder to close. + +This will destroy the decoder object. +*/ void drflac_close(drflac* pFlac); -// Reads sample data from the given FLAC decoder, output as interleaved signed 32-bit PCM. -// -// 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. -// -// Returns the number of PCM frames actually read. -// -// 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. +/* +Reads sample data from the given FLAC decoder, output as interleaved signed 32-bit PCM. + +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. + +Returns the number of PCM frames actually read. + +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_uint64 drflac_read_pcm_frames_s32(drflac* pFlac, drflac_uint64 framesToRead, drflac_int32* pBufferOut); -// Same as drflac_read_pcm_frames_s32(), except outputs samples as 16-bit integer PCM rather than 32-bit. -// -// Note that this is lossy for streams where the bits per sample is larger than 16. +/* +Same as drflac_read_pcm_frames_s32(), except outputs samples as 16-bit integer PCM rather than 32-bit. + +Note that this is lossy for streams where the bits per sample is larger than 16. +*/ drflac_uint64 drflac_read_pcm_frames_s16(drflac* pFlac, drflac_uint64 framesToRead, drflac_int16* pBufferOut); -// Same as drflac_read_pcm_frames_s32(), except outputs samples as 32-bit floating-point PCM. -// -// Note that this should be considered lossy due to the nature of floating point numbers not being able to exactly -// represent every possible number. +/* +Same as drflac_read_pcm_frames_s32(), except outputs samples as 32-bit floating-point PCM. + +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_uint64 drflac_read_pcm_frames_f32(drflac* pFlac, drflac_uint64 framesToRead, float* pBufferOut); -// Seeks to the PCM frame at the given index. -// -// pFlac [in] The decoder. -// pcmFrameIndex [in] The index of the PCM frame to seek to. See notes below. -// -// Returns DRFLAC_TRUE if successful; DRFLAC_FALSE otherwise. +/* +Seeks to the PCM frame at the given index. + +pFlac [in] The decoder. +pcmFrameIndex [in] The index of the PCM frame to seek to. See notes below. + +Returns DRFLAC_TRUE if successful; DRFLAC_FALSE otherwise. +*/ 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. -// -// filename [in] The path of the file to open, either absolute or relative to the current directory. -// -// Returns a pointer to an object representing the decoder. -// -// Close the decoder with drflac_close(). -// -// 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(), drflac_open_file_with_metadata(), drflac_close() +/* +Opens a FLAC decoder from the file at the given path. + +filename [in] The path of the file to open, either absolute or relative to the current directory. + +Returns a pointer to an object representing the decoder. + +Close the decoder with drflac_close(). + +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(), drflac_open_file_with_metadata(), drflac_close() +*/ drflac* drflac_open_file(const char* filename); -// Opens a FLAC decoder from the file at the given path and notifies the caller of the metadata chunks (album art, etc.) -// -// Look at the documentation for drflac_open_with_metadata() for more information on how metadata is handled. +/* +Opens a FLAC decoder from the file at the given path and notifies the caller of the metadata chunks (album art, etc.) + +Look at the documentation for drflac_open_with_metadata() for more information on how metadata is handled. +*/ drflac* drflac_open_file_with_metadata(const char* filename, drflac_meta_proc onMeta, void* pUserData); #endif -// Opens a FLAC decoder from a pre-allocated block of memory -// -// This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for -// the lifetime of the decoder. +/* +Opens a FLAC decoder from a pre-allocated block of memory + +This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for +the lifetime of the decoder. +*/ drflac* drflac_open_memory(const void* data, size_t dataSize); -// Opens a FLAC decoder from a pre-allocated block of memory and notifies the caller of the metadata chunks (album art, etc.) -// -// Look at the documentation for drflac_open_with_metadata() for more information on how metadata is handled. +/* +Opens a FLAC decoder from a pre-allocated block of memory and notifies the caller of the metadata chunks (album art, etc.) + +Look at the documentation for drflac_open_with_metadata() for more information on how metadata is handled. +*/ drflac* drflac_open_memory_with_metadata(const void* data, size_t dataSize, drflac_meta_proc onMeta, void* pUserData); -//// High Level APIs //// +/* 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(). -// -// 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). +/* +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(). + +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_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); -// Same as drflac_open_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. +/* Same as drflac_open_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. */ 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); -// Same as drflac_open_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. +/* Same as drflac_open_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. */ 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); #ifndef DR_FLAC_NO_STDIO -// Same as drflac_open_and_read_pcm_frames_s32() except opens the decoder from a file. +/* Same as drflac_open_and_read_pcm_frames_s32() except opens the decoder from a file. */ drflac_int32* drflac_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount); -// Same as drflac_open_file_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. +/* Same as drflac_open_file_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. */ drflac_int16* drflac_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount); -// Same as drflac_open_file_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. +/* Same as drflac_open_file_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. */ float* drflac_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount); #endif -// Same as drflac_open_and_read_pcm_frames_s32() except opens the decoder from a block of memory. +/* Same as drflac_open_and_read_pcm_frames_s32() except opens the decoder from a block of memory. */ 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); -// Same as drflac_open_memory_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. +/* Same as drflac_open_memory_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. */ 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); -// Same as drflac_open_memory_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. +/* Same as drflac_open_memory_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. */ float* drflac_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount); -// Frees memory that was allocated internally by dr_flac. +/* Frees memory that was allocated internally by dr_flac. */ void drflac_free(void* p); -// Structure representing an iterator for vorbis comments in a VORBIS_COMMENT metadata block. +/* 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. +/* +Initializes a vorbis comment iterator. This can be used for iterating over the vorbis comments in a VORBIS_COMMENT +metadata block. +*/ 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. +/* +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. +*/ 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. +/* 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. +/* 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 { @@ -747,40 +815,44 @@ typedef struct 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. +/* +Initializes a cuesheet track iterator. This can be used for iterating over the cuesheet tracks in a CUESHEET metadata +block. +*/ 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. +/* Goes to the next cuesheet track in the given iterator. If DRFLAC_FALSE is returned it means there are no more comments. */ drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter, drflac_cuesheet_track* pCuesheetTrack); -//// Deprecated APIs //// -DRFLAC_DEPRECATED drflac_uint64 drflac_read_s32(drflac* pFlac, drflac_uint64 samplesToRead, drflac_int32* pBufferOut); // Use drflac_read_pcm_frames_s32() instead. -DRFLAC_DEPRECATED drflac_uint64 drflac_read_s16(drflac* pFlac, drflac_uint64 samplesToRead, drflac_int16* pBufferOut); // Use drflac_read_pcm_frames_s16() instead. -DRFLAC_DEPRECATED drflac_uint64 drflac_read_f32(drflac* pFlac, drflac_uint64 samplesToRead, float* pBufferOut); // Use drflac_read_pcm_frames_f32() instead. -DRFLAC_DEPRECATED drflac_bool32 drflac_seek_to_sample(drflac* pFlac, drflac_uint64 sampleIndex); // Use drflac_seek_to_pcm_frame() instead. -DRFLAC_DEPRECATED drflac_int32* drflac_open_and_decode_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); // Use drflac_open_and_read_pcm_frames_s32(). -DRFLAC_DEPRECATED drflac_int16* drflac_open_and_decode_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); // Use drflac_open_and_read_pcm_frames_s16(). -DRFLAC_DEPRECATED float* drflac_open_and_decode_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); // Use drflac_open_and_read_pcm_frames_f32(). -DRFLAC_DEPRECATED drflac_int32* drflac_open_and_decode_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); // Use drflac_open_file_and_read_pcm_frames_s32(). -DRFLAC_DEPRECATED drflac_int16* drflac_open_and_decode_file_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); // Use drflac_open_file_and_read_pcm_frames_s16(). -DRFLAC_DEPRECATED float* drflac_open_and_decode_file_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); // Use drflac_open_file_and_read_pcm_frames_f32(). -DRFLAC_DEPRECATED drflac_int32* drflac_open_and_decode_memory_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); // Use drflac_open_memory_and_read_pcm_frames_s32(). -DRFLAC_DEPRECATED drflac_int16* drflac_open_and_decode_memory_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); // Use drflac_open_memory_and_read_pcm_frames_s16(). -DRFLAC_DEPRECATED float* drflac_open_and_decode_memory_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); // Use drflac_open_memory_and_read_pcm_frames_f32(). +/* Deprecated APIs */ +DRFLAC_DEPRECATED drflac_uint64 drflac_read_s32(drflac* pFlac, drflac_uint64 samplesToRead, drflac_int32* pBufferOut); /* Use drflac_read_pcm_frames_s32() instead. */ +DRFLAC_DEPRECATED drflac_uint64 drflac_read_s16(drflac* pFlac, drflac_uint64 samplesToRead, drflac_int16* pBufferOut); /* Use drflac_read_pcm_frames_s16() instead. */ +DRFLAC_DEPRECATED drflac_uint64 drflac_read_f32(drflac* pFlac, drflac_uint64 samplesToRead, float* pBufferOut); /* Use drflac_read_pcm_frames_f32() instead. */ +DRFLAC_DEPRECATED drflac_bool32 drflac_seek_to_sample(drflac* pFlac, drflac_uint64 sampleIndex); /* Use drflac_seek_to_pcm_frame() instead. */ +DRFLAC_DEPRECATED drflac_int32* drflac_open_and_decode_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); /* Use drflac_open_and_read_pcm_frames_s32(). */ +DRFLAC_DEPRECATED drflac_int16* drflac_open_and_decode_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); /* Use drflac_open_and_read_pcm_frames_s16(). */ +DRFLAC_DEPRECATED float* drflac_open_and_decode_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); /* Use drflac_open_and_read_pcm_frames_f32(). */ +DRFLAC_DEPRECATED drflac_int32* drflac_open_and_decode_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); /* Use drflac_open_file_and_read_pcm_frames_s32(). */ +DRFLAC_DEPRECATED drflac_int16* drflac_open_and_decode_file_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); /* Use drflac_open_file_and_read_pcm_frames_s16(). */ +DRFLAC_DEPRECATED float* drflac_open_and_decode_file_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); /* Use drflac_open_file_and_read_pcm_frames_f32(). */ +DRFLAC_DEPRECATED drflac_int32* drflac_open_and_decode_memory_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); /* Use drflac_open_memory_and_read_pcm_frames_s32(). */ +DRFLAC_DEPRECATED drflac_int16* drflac_open_and_decode_memory_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); /* Use drflac_open_memory_and_read_pcm_frames_s16(). */ +DRFLAC_DEPRECATED float* drflac_open_and_decode_memory_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalSampleCount); /* Use drflac_open_memory_and_read_pcm_frames_f32(). */ #ifdef __cplusplus } #endif -#endif //dr_flac_h +#endif /* dr_flac_h */ -/////////////////////////////////////////////////////////////////////////////// -// -// IMPLEMENTATION -// -/////////////////////////////////////////////////////////////////////////////// +/************************************************************************************************************************************************************ + ************************************************************************************************************************************************************ + + IMPLEMENTATION + + ************************************************************************************************************************************************************ + ************************************************************************************************************************************************************/ #ifdef DR_FLAC_IMPLEMENTATION /* Disable some annoying warnings. */ @@ -808,13 +880,13 @@ DRFLAC_DEPRECATED float* drflac_open_and_decode_memory_f32(const void* data, siz #define DRFLAC_INLINE __forceinline #else #ifdef __GNUC__ -#define DRFLAC_INLINE inline __attribute__((always_inline)) +#define DRFLAC_INLINE __inline__ __attribute__((always_inline)) #else -#define DRFLAC_INLINE inline +#define DRFLAC_INLINE #endif #endif -// CPU architecture. +/* CPU architecture. */ #if defined(__x86_64__) || defined(_M_X64) #define DRFLAC_X64 #elif defined(__i386) || defined(_M_IX86) @@ -823,19 +895,19 @@ DRFLAC_DEPRECATED float* drflac_open_and_decode_memory_f32(const void* data, siz #define DRFLAC_ARM #endif -// Intrinsics Support +/* Intrinsics Support */ #if !defined(DR_FLAC_NO_SIMD) #if defined(DRFLAC_X64) || defined(DRFLAC_X86) #if defined(_MSC_VER) && !defined(__clang__) - // MSVC. - #if !defined(DRFLAC_NO_SSE2) // Assume all MSVC compilers support SSE2 intrinsics. + /* MSVC. */ + #if !defined(DRFLAC_NO_SSE2) /* Assume all MSVC compilers support SSE2 intrinsics. */ #define DRFLAC_SUPPORT_SSE2 #endif - #if _MSC_VER >= 1600 && !defined(DRFLAC_NO_SSE41) // 2010 + #if _MSC_VER >= 1600 && !defined(DRFLAC_NO_SSE41) /* 2010 */ #define DRFLAC_SUPPORT_SSE41 #endif #else - // Assume GNUC-style. + /* Assume GNUC-style. */ #if defined(__SSE2__) && !defined(DRFLAC_NO_SSE2) #define DRFLAC_SUPPORT_SSE2 #endif @@ -844,7 +916,7 @@ DRFLAC_DEPRECATED float* drflac_open_and_decode_memory_f32(const void* data, siz #endif #endif - // If at this point we still haven't determined compiler support for the intrinsics just fall back to __has_include. + /* If at this point we still haven't determined compiler support for the intrinsics just fall back to __has_include. */ #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include) #if !defined(DRFLAC_SUPPORT_SSE2) && !defined(DRFLAC_NO_SSE2) && __has_include() #define DRFLAC_SUPPORT_SSE2 @@ -866,7 +938,7 @@ DRFLAC_DEPRECATED float* drflac_open_and_decode_memory_f32(const void* data, siz #define DRFLAC_SUPPORT_NEON #endif - // Fall back to looking for the #include file. + /* Fall back to looking for the #include file. */ #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include) #if !defined(DRFLAC_SUPPORT_NEON) && !defined(DRFLAC_NO_NEON) && __has_include() #define DRFLAC_SUPPORT_NEON @@ -879,7 +951,7 @@ DRFLAC_DEPRECATED float* drflac_open_and_decode_memory_f32(const void* data, siz #endif #endif -// Compile-time CPU feature support. +/* Compile-time CPU feature support. */ #if !defined(DR_FLAC_NO_SIMD) && (defined(DRFLAC_X86) || defined(DRFLAC_X64)) #if defined(_MSC_VER) && !defined(__clang__) #if _MSC_VER >= 1400 @@ -895,11 +967,13 @@ DRFLAC_DEPRECATED float* drflac_open_and_decode_memory_f32(const void* data, siz #if defined(__GNUC__) || defined(__clang__) static void drflac__cpuid(int info[4], int fid) { - // It looks like the -fPIC option uses the ebx register which GCC complains about. We can work around this by just using a different register, the - // specific register of which I'm letting the compiler decide on. The "k" prefix is used to specify a 32-bit register. The {...} syntax is for - // supporting different assembly dialects. - // - // What's basically happening is that we're saving and restoring the ebx register manually. + /* + It looks like the -fPIC option uses the ebx register which GCC complains about. We can work around this by just using a different register, the + specific register of which I'm letting the compiler decide on. The "k" prefix is used to specify a 32-bit register. The {...} syntax is for + supporting different assembly dialects. + + What's basically happening is that we're saving and restoring the ebx register manually. + */ #if defined(DRFLAC_X86) && defined(__PIC__) __asm__ __volatile__ ( "xchg{l} {%%}ebx, %k1;" @@ -926,9 +1000,9 @@ static DRFLAC_INLINE drflac_bool32 drflac_has_sse2() #if defined(DRFLAC_SUPPORT_SSE2) #if (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(DRFLAC_NO_SSE2) #if defined(DRFLAC_X64) - return DRFLAC_TRUE; // 64-bit targets always support SSE2. + return DRFLAC_TRUE; /* 64-bit targets always support SSE2. */ #elif (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__) - return DRFLAC_TRUE; // If the compiler is allowed to freely generate SSE2 code we can assume support. + return DRFLAC_TRUE; /* If the compiler is allowed to freely generate SSE2 code we can assume support. */ #else #if defined(DRFLAC_NO_CPUID) return DRFLAC_FALSE; @@ -939,10 +1013,10 @@ static DRFLAC_INLINE drflac_bool32 drflac_has_sse2() #endif #endif #else - return DRFLAC_FALSE; // SSE2 is only supported on x86 and x64 architectures. + return DRFLAC_FALSE; /* SSE2 is only supported on x86 and x64 architectures. */ #endif #else - return DRFLAC_FALSE; // No compiler support. + return DRFLAC_FALSE; /* No compiler support. */ #endif } @@ -951,9 +1025,9 @@ static DRFLAC_INLINE drflac_bool32 drflac_has_sse41() #if defined(DRFLAC_SUPPORT_SSE41) #if (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(DRFLAC_NO_SSE41) #if defined(DRFLAC_X64) - return DRFLAC_TRUE; // 64-bit targets always support SSE4.1. + return DRFLAC_TRUE; /* 64-bit targets always support SSE4.1. */ #elif (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE4_1__) - return DRFLAC_TRUE; // If the compiler is allowed to freely generate SSE41 code we can assume support. + return DRFLAC_TRUE; /* If the compiler is allowed to freely generate SSE41 code we can assume support. */ #else #if defined(DRFLAC_NO_CPUID) return DRFLAC_FALSE; @@ -964,10 +1038,10 @@ static DRFLAC_INLINE drflac_bool32 drflac_has_sse41() #endif #endif #else - return DRFLAC_FALSE; // SSE41 is only supported on x86 and x64 architectures. + return DRFLAC_FALSE; /* SSE41 is only supported on x86 and x64 architectures. */ #endif #else - return DRFLAC_FALSE; // No compiler support. + return DRFLAC_FALSE; /* No compiler support. */ #endif } @@ -1007,7 +1081,7 @@ static DRFLAC_INLINE drflac_bool32 drflac_has_sse41() #endif -// Standard library stuff. +/* Standard library stuff. */ #ifndef DRFLAC_ASSERT #include #define DRFLAC_ASSERT(expression) assert(expression) @@ -1028,11 +1102,11 @@ static DRFLAC_INLINE drflac_bool32 drflac_has_sse41() #define DRFLAC_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) #endif -#define DRFLAC_MAX_SIMD_VECTOR_SIZE 64 // 64 for AVX-512 in the future. +#define DRFLAC_MAX_SIMD_VECTOR_SIZE 64 /* 64 for AVX-512 in the future. */ typedef drflac_int32 drflac_result; #define DRFLAC_SUCCESS 0 -#define DRFLAC_ERROR -1 // A generic error. +#define DRFLAC_ERROR -1 /* A generic error. */ #define DRFLAC_INVALID_ARGS -2 #define DRFLAC_END_OF_STREAM -128 #define DRFLAC_CRC_MISMATCH -129 @@ -1051,8 +1125,10 @@ typedef drflac_int32 drflac_result; #define DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE 9 #define DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE 10 -// Keeps track of the number of leading samples for each sub-frame. This is required because the SSE pipeline will occasionally -// reference excess prior samples. +/* +Keeps track of the number of leading samples for each sub-frame. This is required because the SSE pipeline will occasionally +reference excess prior samples. +*/ #define DRFLAC_LEADING_SAMPLES 32 @@ -1062,7 +1138,7 @@ typedef drflac_int32 drflac_result; #define drflac_zero_memory DRFLAC_ZERO_MEMORY -// CPU caps. +/* CPU caps. */ static drflac_bool32 drflac__gIsLZCNTSupported = DRFLAC_FALSE; #ifndef DRFLAC_NO_CPUID static drflac_bool32 drflac__gIsSSE2Supported = DRFLAC_FALSE; @@ -1071,20 +1147,20 @@ static void drflac__init_cpu_caps() { int info[4] = {0}; - // LZCNT + /* LZCNT */ drflac__cpuid(info, 0x80000001); drflac__gIsLZCNTSupported = (info[2] & (1 << 5)) != 0; - // SSE2 + /* SSE2 */ drflac__gIsSSE2Supported = drflac_has_sse2(); - // SSE4.1 + /* SSE4.1 */ drflac__gIsSSE41Supported = drflac_has_sse41(); } #endif -//// Endian Management //// +/* Endian Management */ static DRFLAC_INLINE drflac_bool32 drflac__is_little_endian() { #if defined(DRFLAC_X86) || defined(DRFLAC_X64) @@ -1205,7 +1281,7 @@ static DRFLAC_INLINE drflac_uint32 drflac__unsynchsafe_32(drflac_uint32 n) -// The CRC code below is based on this document: http://zlib.net/crc_v3.txt +/* The CRC code below is based on this document: http://zlib.net/crc_v3.txt */ static drflac_uint8 drflac__crc8_table[] = { 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, @@ -1267,8 +1343,6 @@ static DRFLAC_INLINE drflac_uint8 drflac_crc8_byte(drflac_uint8 crc, drflac_uint static DRFLAC_INLINE drflac_uint8 drflac_crc8(drflac_uint8 crc, drflac_uint32 data, drflac_uint32 count) { - drflac_assert(count <= 32); - #ifdef DR_FLAC_NO_CRC (void)crc; (void)data; @@ -1276,7 +1350,7 @@ static DRFLAC_INLINE drflac_uint8 drflac_crc8(drflac_uint8 crc, drflac_uint32 da return 0; #else #if 0 - // REFERENCE (use of this implementation requires an explicit flush by doing "drflac_crc8(crc, 0, 8);") + /* REFERENCE (use of this implementation requires an explicit flush by doing "drflac_crc8(crc, 0, 8);") */ drflac_uint8 p = 0x07; for (int i = count-1; i >= 0; --i) { drflac_uint8 bit = (data & (1 << i)) >> i; @@ -1288,13 +1362,19 @@ static DRFLAC_INLINE drflac_uint8 drflac_crc8(drflac_uint8 crc, drflac_uint32 da } return crc; #else - drflac_uint32 wholeBytes = count >> 3; - drflac_uint32 leftoverBits = count - (wholeBytes*8); + drflac_uint32 wholeBytes; + drflac_uint32 leftoverBits; + drflac_uint64 leftoverDataMask; static drflac_uint64 leftoverDataMaskTable[8] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F }; - drflac_uint64 leftoverDataMask = leftoverDataMaskTable[leftoverBits]; + + drflac_assert(count <= 32); + + wholeBytes = count >> 3; + leftoverBits = count - (wholeBytes*8); + leftoverDataMask = leftoverDataMaskTable[leftoverBits]; switch (wholeBytes) { case 4: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0xFF000000UL << leftoverBits)) >> (24 + leftoverBits))); @@ -1334,8 +1414,6 @@ static DRFLAC_INLINE drflac_uint16 drflac_crc16_bytes(drflac_uint16 crc, drflac_ static DRFLAC_INLINE drflac_uint16 drflac_crc16__32bit(drflac_uint16 crc, drflac_uint32 data, drflac_uint32 count) { - drflac_assert(count <= 64); - #ifdef DR_FLAC_NO_CRC (void)crc; (void)data; @@ -1343,7 +1421,7 @@ static DRFLAC_INLINE drflac_uint16 drflac_crc16__32bit(drflac_uint16 crc, drflac return 0; #else #if 0 - // REFERENCE (use of this implementation requires an explicit flush by doing "drflac_crc16(crc, 0, 16);") + /* REFERENCE (use of this implementation requires an explicit flush by doing "drflac_crc16(crc, 0, 16);") */ drflac_uint16 p = 0x8005; for (int i = count-1; i >= 0; --i) { drflac_uint16 bit = (data & (1ULL << i)) >> i; @@ -1356,13 +1434,19 @@ static DRFLAC_INLINE drflac_uint16 drflac_crc16__32bit(drflac_uint16 crc, drflac return crc; #else - drflac_uint32 wholeBytes = count >> 3; - drflac_uint32 leftoverBits = count - (wholeBytes*8); + drflac_uint32 wholeBytes; + drflac_uint32 leftoverBits; + drflac_uint64 leftoverDataMask; static drflac_uint64 leftoverDataMaskTable[8] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F }; - drflac_uint64 leftoverDataMask = leftoverDataMaskTable[leftoverBits]; + + drflac_assert(count <= 64); + + wholeBytes = count >> 3; + leftoverBits = count - (wholeBytes*8); + leftoverDataMask = leftoverDataMaskTable[leftoverBits]; switch (wholeBytes) { default: @@ -1379,32 +1463,36 @@ static DRFLAC_INLINE drflac_uint16 drflac_crc16__32bit(drflac_uint16 crc, drflac static DRFLAC_INLINE drflac_uint16 drflac_crc16__64bit(drflac_uint16 crc, drflac_uint64 data, drflac_uint32 count) { - drflac_assert(count <= 64); - #ifdef DR_FLAC_NO_CRC (void)crc; (void)data; (void)count; return 0; #else - drflac_uint32 wholeBytes = count >> 3; - drflac_uint32 leftoverBits = count - (wholeBytes*8); + drflac_uint32 wholeBytes; + drflac_uint32 leftoverBits; + drflac_uint64 leftoverDataMask; static drflac_uint64 leftoverDataMaskTable[8] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F }; - drflac_uint64 leftoverDataMask = leftoverDataMaskTable[leftoverBits]; + + drflac_assert(count <= 64); + + wholeBytes = count >> 3; + leftoverBits = count - (wholeBytes*8); + leftoverDataMask = leftoverDataMaskTable[leftoverBits]; switch (wholeBytes) { default: - case 8: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & ((drflac_uint64)0xFF00000000000000 << leftoverBits)) >> (56 + leftoverBits))); - case 7: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & ((drflac_uint64)0x00FF000000000000 << leftoverBits)) >> (48 + leftoverBits))); - case 6: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & ((drflac_uint64)0x0000FF0000000000 << leftoverBits)) >> (40 + leftoverBits))); - case 5: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & ((drflac_uint64)0x000000FF00000000 << leftoverBits)) >> (32 + leftoverBits))); - case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & ((drflac_uint64)0x00000000FF000000 << leftoverBits)) >> (24 + leftoverBits))); - case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & ((drflac_uint64)0x0000000000FF0000 << leftoverBits)) >> (16 + leftoverBits))); - case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & ((drflac_uint64)0x000000000000FF00 << leftoverBits)) >> ( 8 + leftoverBits))); - case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & ((drflac_uint64)0x00000000000000FF << leftoverBits)) >> ( 0 + leftoverBits))); + case 8: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0xFF000000 << 16 << 16) << leftoverBits)) >> (56 + leftoverBits))); /* Weird "16 << 16" bitshift is required for C89 because it doesn't support 64-bit constants. Should be optimized out by a good compiler. */ + case 7: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x00FF0000 << 16 << 16) << leftoverBits)) >> (48 + leftoverBits))); + case 6: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x0000FF00 << 16 << 16) << leftoverBits)) >> (40 + leftoverBits))); + case 5: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x000000FF << 16 << 16) << leftoverBits)) >> (32 + leftoverBits))); + case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0xFF000000 ) << leftoverBits)) >> (24 + leftoverBits))); + case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x00FF0000 ) << leftoverBits)) >> (16 + leftoverBits))); + case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x0000FF00 ) << leftoverBits)) >> ( 8 + leftoverBits))); + case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x000000FF ) << leftoverBits)) >> ( 0 + leftoverBits))); case 0: if (leftoverBits > 0) crc = (crc << leftoverBits) ^ drflac__crc16_table[(crc >> (16 - leftoverBits)) ^ (data & leftoverDataMask)]; } return crc; @@ -1428,13 +1516,15 @@ static DRFLAC_INLINE drflac_uint16 drflac_crc16(drflac_uint16 crc, drflac_cache_ #define drflac__be2host__cache_line drflac__be2host_32 #endif -// BIT READING ATTEMPT #2 -// -// This uses a 32- or 64-bit bit-shifted cache - as bits are read, the cache is shifted such that the first valid bit is sitting -// on the most significant bit. It uses the notion of an L1 and L2 cache (borrowed from CPU architecture), where the L1 cache -// is a 32- or 64-bit unsigned integer (depending on whether or not a 32- or 64-bit build is being compiled) and the L2 is an -// array of "cache lines", with each cache line being the same size as the L1. The L2 is a buffer of about 4KB and is where data -// from onRead() is read into. +/* +BIT READING ATTEMPT #2 + +This uses a 32- or 64-bit bit-shifted cache - as bits are read, the cache is shifted such that the first valid bit is sitting +on the most significant bit. It uses the notion of an L1 and L2 cache (borrowed from CPU architecture), where the L1 cache +is a 32- or 64-bit unsigned integer (depending on whether or not a 32- or 64-bit build is being compiled) and the L2 is an +array of "cache lines", with each cache line being the same size as the L1. The L2 is a buffer of about 4KB and is where data +from onRead() is read into. +*/ #define DRFLAC_CACHE_L1_SIZE_BYTES(bs) (sizeof((bs)->cache)) #define DRFLAC_CACHE_L1_SIZE_BITS(bs) (sizeof((bs)->cache)*8) #define DRFLAC_CACHE_L1_BITS_REMAINING(bs) (DRFLAC_CACHE_L1_SIZE_BITS(bs) - (bs)->consumedBits) @@ -1463,19 +1553,23 @@ static DRFLAC_INLINE void drflac__update_crc16(drflac_bs* bs) static DRFLAC_INLINE drflac_uint16 drflac__flush_crc16(drflac_bs* bs) { - // We should never be flushing in a situation where we are not aligned on a byte boundary. + /* We should never be flushing in a situation where we are not aligned on a byte boundary. */ drflac_assert((DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7) == 0); - // The bits that were read from the L1 cache need to be accumulated. The number of bytes needing to be accumulated is determined - // by the number of bits that have been consumed. + /* + The bits that were read from the L1 cache need to be accumulated. The number of bytes needing to be accumulated is determined + by the number of bits that have been consumed. + */ if (DRFLAC_CACHE_L1_BITS_REMAINING(bs) == 0) { drflac__update_crc16(bs); } else { - // We only accumulate the consumed bits. + /* We only accumulate the consumed bits. */ bs->crc16 = drflac_crc16_bytes(bs->crc16, bs->crc16Cache >> DRFLAC_CACHE_L1_BITS_REMAINING(bs), (bs->consumedBits >> 3) - bs->crc16CacheIgnoredBytes); - // The bits that we just accumulated should never be accumulated again. We need to keep track of how many bytes were accumulated - // so we can handle that later. + /* + The bits that we just accumulated should never be accumulated again. We need to keep track of how many bytes were accumulated + so we can handle that later. + */ bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3; } @@ -1485,19 +1579,24 @@ static DRFLAC_INLINE drflac_uint16 drflac__flush_crc16(drflac_bs* bs) static DRFLAC_INLINE drflac_bool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs) { - // Fast path. Try loading straight from L2. + size_t bytesRead; + size_t alignedL1LineCount; + + /* Fast path. Try loading straight from L2. */ if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { bs->cache = bs->cacheL2[bs->nextL2Line++]; return DRFLAC_TRUE; } - // If we get here it means we've run out of data in the L2 cache. We'll need to fetch more from the client, if there's - // any left. + /* + If we get here it means we've run out of data in the L2 cache. We'll need to fetch more from the client, if there's + any left. + */ if (bs->unalignedByteCount > 0) { - return DRFLAC_FALSE; // If we have any unaligned bytes it means there's no more aligned bytes left in the client. + return DRFLAC_FALSE; /* If we have any unaligned bytes it means there's no more aligned bytes left in the client. */ } - size_t bytesRead = bs->onRead(bs->pUserData, bs->cacheL2, DRFLAC_CACHE_L2_SIZE_BYTES(bs)); + bytesRead = bs->onRead(bs->pUserData, bs->cacheL2, DRFLAC_CACHE_L2_SIZE_BYTES(bs)); bs->nextL2Line = 0; if (bytesRead == DRFLAC_CACHE_L2_SIZE_BYTES(bs)) { @@ -1506,13 +1605,15 @@ static DRFLAC_INLINE drflac_bool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs } - // If we get here it means we were unable to retrieve enough data to fill the entire L2 cache. It probably - // means we've just reached the end of the file. We need to move the valid data down to the end of the buffer - // and adjust the index of the next line accordingly. Also keep in mind that the L2 cache must be aligned to - // the size of the L1 so we'll need to seek backwards by any misaligned bytes. - size_t alignedL1LineCount = bytesRead / DRFLAC_CACHE_L1_SIZE_BYTES(bs); + /* + If we get here it means we were unable to retrieve enough data to fill the entire L2 cache. It probably + means we've just reached the end of the file. We need to move the valid data down to the end of the buffer + and adjust the index of the next line accordingly. Also keep in mind that the L2 cache must be aligned to + the size of the L1 so we'll need to seek backwards by any misaligned bytes. + */ + alignedL1LineCount = bytesRead / DRFLAC_CACHE_L1_SIZE_BYTES(bs); - // We need to keep track of any unaligned bytes for later use. + /* We need to keep track of any unaligned bytes for later use. */ bs->unalignedByteCount = bytesRead - (alignedL1LineCount * DRFLAC_CACHE_L1_SIZE_BYTES(bs)); if (bs->unalignedByteCount > 0) { bs->unalignedCache = bs->cacheL2[alignedL1LineCount]; @@ -1520,7 +1621,8 @@ static DRFLAC_INLINE drflac_bool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs if (alignedL1LineCount > 0) { size_t offset = DRFLAC_CACHE_L2_LINE_COUNT(bs) - alignedL1LineCount; - for (size_t i = alignedL1LineCount; i > 0; --i) { + size_t i; + for (i = alignedL1LineCount; i > 0; --i) { bs->cacheL2[i-1 + offset] = bs->cacheL2[i-1]; } @@ -1528,7 +1630,7 @@ static DRFLAC_INLINE drflac_bool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs bs->cache = bs->cacheL2[bs->nextL2Line++]; return DRFLAC_TRUE; } else { - // If we get into this branch it means we weren't able to load any L1-aligned data. + /* If we get into this branch it means we weren't able to load any L1-aligned data. */ bs->nextL2Line = DRFLAC_CACHE_L2_LINE_COUNT(bs); return DRFLAC_FALSE; } @@ -1536,11 +1638,13 @@ static DRFLAC_INLINE drflac_bool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs static drflac_bool32 drflac__reload_cache(drflac_bs* bs) { + size_t bytesRead; + #ifndef DR_FLAC_NO_CRC drflac__update_crc16(bs); #endif - // Fast path. Try just moving the next value in the L2 cache to the L1 cache. + /* Fast path. Try just moving the next value in the L2 cache to the L1 cache. */ if (drflac__reload_l1_cache_from_l2(bs)) { bs->cache = drflac__be2host__cache_line(bs->cache); bs->consumedBits = 0; @@ -1550,14 +1654,16 @@ static drflac_bool32 drflac__reload_cache(drflac_bs* bs) return DRFLAC_TRUE; } - // Slow path. + /* Slow path. */ - // If we get here it means we have failed to load the L1 cache from the L2. Likely we've just reached the end of the stream and the last - // few bytes did not meet the alignment requirements for the L2 cache. In this case we need to fall back to a slower path and read the - // data from the unaligned cache. - size_t bytesRead = bs->unalignedByteCount; + /* + If we get here it means we have failed to load the L1 cache from the L2. Likely we've just reached the end of the stream and the last + few bytes did not meet the alignment requirements for the L2 cache. In this case we need to fall back to a slower path and read the + data from the unaligned cache. + */ + bytesRead = bs->unalignedByteCount; if (bytesRead == 0) { - bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs); // <-- The stream has been exhausted, so marked the bits as consumed. + bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs); /* <-- The stream has been exhausted, so marked the bits as consumed. */ return DRFLAC_FALSE; } @@ -1565,8 +1671,8 @@ static drflac_bool32 drflac__reload_cache(drflac_bs* bs) bs->consumedBits = (drflac_uint32)(DRFLAC_CACHE_L1_SIZE_BYTES(bs) - bytesRead) * 8; bs->cache = drflac__be2host__cache_line(bs->unalignedCache); - bs->cache &= DRFLAC_CACHE_L1_SELECTION_MASK(DRFLAC_CACHE_L1_BITS_REMAINING(bs)); // <-- Make sure the consumed bits are always set to zero. Other parts of the library depend on this property. - bs->unalignedByteCount = 0; // <-- At this point the unaligned bytes have been moved into the cache and we thus have no more unaligned bytes. + bs->cache &= DRFLAC_CACHE_L1_SELECTION_MASK(DRFLAC_CACHE_L1_BITS_REMAINING(bs)); /* <-- Make sure the consumed bits are always set to zero. Other parts of the library depend on this property. */ + bs->unalignedByteCount = 0; /* <-- At this point the unaligned bytes have been moved into the cache and we thus have no more unaligned bytes. */ #ifndef DR_FLAC_NO_CRC bs->crc16Cache = bs->cache >> bs->consumedBits; @@ -1577,10 +1683,10 @@ static drflac_bool32 drflac__reload_cache(drflac_bs* bs) static void drflac__reset_cache(drflac_bs* bs) { - bs->nextL2Line = DRFLAC_CACHE_L2_LINE_COUNT(bs); // <-- This clears the L2 cache. - bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs); // <-- This clears the L1 cache. + bs->nextL2Line = DRFLAC_CACHE_L2_LINE_COUNT(bs); /* <-- This clears the L2 cache. */ + bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs); /* <-- This clears the L1 cache. */ bs->cache = 0; - bs->unalignedByteCount = 0; // <-- This clears the trailing unaligned bytes. + bs->unalignedByteCount = 0; /* <-- This clears the trailing unaligned bytes. */ bs->unalignedCache = 0; #ifndef DR_FLAC_NO_CRC @@ -1604,9 +1710,11 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_uint32(drflac_bs* bs, unsigned i } if (bitCount <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { - // If we want to load all 32-bits from a 32-bit cache we need to do it slightly differently because we can't do - // a 32-bit shift on a 32-bit integer. This will never be the case on 64-bit caches, so we can have a slightly - // more optimal solution for this. + /* + If we want to load all 32-bits from a 32-bit cache we need to do it slightly differently because we can't do + a 32-bit shift on a 32-bit integer. This will never be the case on 64-bit caches, so we can have a slightly + more optimal solution for this. + */ #ifdef DRFLAC_64BIT *pResultOut = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCount); bs->consumedBits += bitCount; @@ -1617,7 +1725,7 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_uint32(drflac_bs* bs, unsigned i bs->consumedBits += bitCount; bs->cache <<= bitCount; } else { - // Cannot shift by 32-bits, so need to do it differently. + /* Cannot shift by 32-bits, so need to do it differently. */ *pResultOut = (drflac_uint32)bs->cache; bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs); bs->cache = 0; @@ -1626,7 +1734,7 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_uint32(drflac_bs* bs, unsigned i return DRFLAC_TRUE; } else { - // It straddles the cached data. It will never cover more than the next chunk. We just read the number in two parts and combine them. + /* It straddles the cached data. It will never cover more than the next chunk. We just read the number in two parts and combine them. */ drflac_uint32 bitCountHi = DRFLAC_CACHE_L1_BITS_REMAINING(bs); drflac_uint32 bitCountLo = bitCount - bitCountHi; drflac_uint32 resultHi = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountHi); @@ -1644,17 +1752,19 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_uint32(drflac_bs* bs, unsigned i static drflac_bool32 drflac__read_int32(drflac_bs* bs, unsigned int bitCount, drflac_int32* pResult) { + drflac_uint32 result; + drflac_uint32 signbit; + drflac_assert(bs != NULL); drflac_assert(pResult != NULL); drflac_assert(bitCount > 0); drflac_assert(bitCount <= 32); - drflac_uint32 result; if (!drflac__read_uint32(bs, bitCount, &result)) { return DRFLAC_FALSE; } - drflac_uint32 signbit = ((result >> (bitCount-1)) & 0x01); + signbit = ((result >> (bitCount-1)) & 0x01); result |= (~signbit + 1) << bitCount; *pResult = (drflac_int32)result; @@ -1664,15 +1774,16 @@ static drflac_bool32 drflac__read_int32(drflac_bs* bs, unsigned int bitCount, dr #ifdef DRFLAC_64BIT static drflac_bool32 drflac__read_uint64(drflac_bs* bs, unsigned int bitCount, drflac_uint64* pResultOut) { + drflac_uint32 resultHi; + drflac_uint32 resultLo; + drflac_assert(bitCount <= 64); drflac_assert(bitCount > 32); - drflac_uint32 resultHi; if (!drflac__read_uint32(bs, bitCount - 32, &resultHi)) { return DRFLAC_FALSE; } - drflac_uint32 resultLo; if (!drflac__read_uint32(bs, 32, &resultLo)) { return DRFLAC_FALSE; } @@ -1682,18 +1793,20 @@ static drflac_bool32 drflac__read_uint64(drflac_bs* bs, unsigned int bitCount, d } #endif -// Function below is unused, but leaving it here in case I need to quickly add it again. +/* Function below is unused, but leaving it here in case I need to quickly add it again. */ #if 0 static drflac_bool32 drflac__read_int64(drflac_bs* bs, unsigned int bitCount, drflac_int64* pResultOut) { + drflac_uint64 result; + drflac_uint64 signbit; + drflac_assert(bitCount <= 64); - drflac_uint64 result; if (!drflac__read_uint64(bs, bitCount, &result)) { return DRFLAC_FALSE; } - drflac_uint64 signbit = ((result >> (bitCount-1)) & 0x01); + signbit = ((result >> (bitCount-1)) & 0x01); result |= (~signbit + 1) << bitCount; *pResultOut = (drflac_int64)result; @@ -1703,12 +1816,13 @@ static drflac_bool32 drflac__read_int64(drflac_bs* bs, unsigned int bitCount, dr static drflac_bool32 drflac__read_uint16(drflac_bs* bs, unsigned int bitCount, drflac_uint16* pResult) { + drflac_uint32 result; + drflac_assert(bs != NULL); drflac_assert(pResult != NULL); drflac_assert(bitCount > 0); drflac_assert(bitCount <= 16); - drflac_uint32 result; if (!drflac__read_uint32(bs, bitCount, &result)) { return DRFLAC_FALSE; } @@ -1720,12 +1834,13 @@ static drflac_bool32 drflac__read_uint16(drflac_bs* bs, unsigned int bitCount, d #if 0 static drflac_bool32 drflac__read_int16(drflac_bs* bs, unsigned int bitCount, drflac_int16* pResult) { + drflac_int32 result; + drflac_assert(bs != NULL); drflac_assert(pResult != NULL); drflac_assert(bitCount > 0); drflac_assert(bitCount <= 16); - drflac_int32 result; if (!drflac__read_int32(bs, bitCount, &result)) { return DRFLAC_FALSE; } @@ -1737,12 +1852,13 @@ static drflac_bool32 drflac__read_int16(drflac_bs* bs, unsigned int bitCount, dr static drflac_bool32 drflac__read_uint8(drflac_bs* bs, unsigned int bitCount, drflac_uint8* pResult) { + drflac_uint32 result; + drflac_assert(bs != NULL); drflac_assert(pResult != NULL); drflac_assert(bitCount > 0); drflac_assert(bitCount <= 8); - drflac_uint32 result; if (!drflac__read_uint32(bs, bitCount, &result)) { return DRFLAC_FALSE; } @@ -1753,12 +1869,13 @@ static drflac_bool32 drflac__read_uint8(drflac_bs* bs, unsigned int bitCount, dr static drflac_bool32 drflac__read_int8(drflac_bs* bs, unsigned int bitCount, drflac_int8* pResult) { + drflac_int32 result; + drflac_assert(bs != NULL); drflac_assert(pResult != NULL); drflac_assert(bitCount > 0); drflac_assert(bitCount <= 8); - drflac_int32 result; if (!drflac__read_int32(bs, bitCount, &result)) { return DRFLAC_FALSE; } @@ -1775,12 +1892,12 @@ static drflac_bool32 drflac__seek_bits(drflac_bs* bs, size_t 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. + /* 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. + /* 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; @@ -1799,7 +1916,7 @@ static drflac_bool32 drflac__seek_bits(drflac_bs* bs, size_t bitsToSeek) } #endif - // Whole leftover bytes. + /* Whole leftover bytes. */ while (bitsToSeek >= 8) { drflac_uint8 bin; if (!drflac__read_uint8(bs, 8, &bin)) { @@ -1808,13 +1925,13 @@ static drflac_bool32 drflac__seek_bits(drflac_bs* bs, size_t bitsToSeek) bitsToSeek -= 8; } - // Leftover bits. + /* 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. + bitsToSeek = 0; /* <-- Necessary for the assert below. */ } drflac_assert(bitsToSeek == 0); @@ -1823,23 +1940,26 @@ static drflac_bool32 drflac__seek_bits(drflac_bs* bs, size_t bitsToSeek) } -// 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. +/* 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. + /* + 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 - drflac_uint8 hi; if (!drflac__read_uint8(bs, 8, &hi)) { return DRFLAC_FALSE; } @@ -1860,8 +1980,8 @@ static drflac_bool32 drflac__find_and_seek_to_next_sync_code(drflac_bs* bs) } } - // Should never get here. - //return DRFLAC_FALSE; + /* Should never get here. */ + /*return DRFLAC_FALSE;*/ } @@ -1874,10 +1994,7 @@ static drflac_bool32 drflac__find_and_seek_to_next_sync_code(drflac_bs* bs) static DRFLAC_INLINE drflac_uint32 drflac__clz_software(drflac_cache_t x) { - if (x == 0) { - return sizeof(x)*8; - } - + drflac_uint32 n; static drflac_uint32 clz_table_4[] = { 0, 4, @@ -1886,7 +2003,11 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz_software(drflac_cache_t x) 1, 1, 1, 1, 1, 1, 1, 1 }; - drflac_uint32 n = clz_table_4[x >> (sizeof(x)*8 - 4)]; + if (x == 0) { + return sizeof(x)*8; + } + + n = clz_table_4[x >> (sizeof(x)*8 - 4)]; if (n == 0) { #ifdef DRFLAC_64BIT if ((x & 0xFFFFFFFF00000000ULL) == 0) { n = 32; x <<= 32; } @@ -1907,7 +2028,7 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz_software(drflac_cache_t x) #ifdef DRFLAC_IMPLEMENT_CLZ_LZCNT static DRFLAC_INLINE drflac_bool32 drflac__is_lzcnt_supported() { - // If the compiler itself does not support the intrinsic then we'll need to return false. + /* If the compiler itself does not support the intrinsic then we'll need to return false. */ #ifdef DRFLAC_HAS_LZCNT_INTRINSIC return drflac__gIsLZCNTSupported; #else @@ -1934,7 +2055,7 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz_lzcnt(drflac_cache_t x) return (drflac_uint32)__builtin_clzl((unsigned long)x); #endif #else - // Unsupported compiler. + /* Unsupported compiler. */ #error "This compiler does not support the lzcnt intrinsic." #endif #endif @@ -1942,15 +2063,16 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz_lzcnt(drflac_cache_t x) #endif #ifdef DRFLAC_IMPLEMENT_CLZ_MSVC -#include // For BitScanReverse(). +#include /* For BitScanReverse(). */ static DRFLAC_INLINE drflac_uint32 drflac__clz_msvc(drflac_cache_t x) { + drflac_uint32 n; + if (x == 0) { return sizeof(x)*8; } - drflac_uint32 n; #ifdef DRFLAC_64BIT _BitScanReverse64((unsigned long*)&n, x); #else @@ -1977,9 +2099,11 @@ static DRFLAC_INLINE drflac_uint32 drflac__clz(drflac_cache_t x) } -static inline drflac_bool32 drflac__seek_past_next_set_bit(drflac_bs* bs, unsigned int* pOffsetOut) +static DRFLAC_INLINE drflac_bool32 drflac__seek_past_next_set_bit(drflac_bs* bs, unsigned int* pOffsetOut) { drflac_uint32 zeroCounter = 0; + drflac_uint32 setBitOffsetPlus1; + while (bs->cache == 0) { zeroCounter += (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs); if (!drflac__reload_cache(bs)) { @@ -1987,7 +2111,7 @@ static inline drflac_bool32 drflac__seek_past_next_set_bit(drflac_bs* bs, unsign } } - drflac_uint32 setBitOffsetPlus1 = drflac__clz(bs->cache); + setBitOffsetPlus1 = drflac__clz(bs->cache); setBitOffsetPlus1 += 1; bs->consumedBits += setBitOffsetPlus1; @@ -2004,9 +2128,11 @@ static drflac_bool32 drflac__seek_to_byte(drflac_bs* bs, drflac_uint64 offsetFro drflac_assert(bs != NULL); drflac_assert(offsetFromStart > 0); - // Seeking from the start is not quite as trivial as it sounds because the onSeek callback takes a signed 32-bit integer (which - // is intentional because it simplifies the implementation of the onSeek callbacks), however offsetFromStart is unsigned 64-bit. - // To resolve we just need to do an initial seek from the start, and then a series of offset seeks to make up the remainder. + /* + Seeking from the start is not quite as trivial as it sounds because the onSeek callback takes a signed 32-bit integer (which + is intentional because it simplifies the implementation of the onSeek callbacks), however offsetFromStart is unsigned 64-bit. + To resolve we just need to do an initial seek from the start, and then a series of offset seeks to make up the remainder. + */ if (offsetFromStart > 0x7FFFFFFF) { drflac_uint64 bytesRemaining = offsetFromStart; if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) { @@ -2032,7 +2158,7 @@ static drflac_bool32 drflac__seek_to_byte(drflac_bs* bs, drflac_uint64 offsetFro } } - // The cache should be reset to force a reload of fresh data from the client. + /* The cache should be reset to force a reload of fresh data from the client. */ drflac__reset_cache(bs); return DRFLAC_TRUE; } @@ -2040,12 +2166,18 @@ static drflac_bool32 drflac__seek_to_byte(drflac_bs* bs, drflac_uint64 offsetFro static drflac_result drflac__read_utf8_coded_number(drflac_bs* bs, drflac_uint64* pNumberOut, drflac_uint8* pCRCOut) { + drflac_uint8 crc; + drflac_uint64 result; + unsigned char utf8[7] = {0}; + int byteCount; + int i; + drflac_assert(bs != NULL); drflac_assert(pNumberOut != NULL); + drflac_assert(pCRCOut != NULL); - drflac_uint8 crc = *pCRCOut; + crc = *pCRCOut; - unsigned char utf8[7] = {0}; if (!drflac__read_uint8(bs, 8, utf8)) { *pNumberOut = 0; return DRFLAC_END_OF_STREAM; @@ -2058,7 +2190,7 @@ static drflac_result drflac__read_utf8_coded_number(drflac_bs* bs, drflac_uint64 return DRFLAC_SUCCESS; } - int byteCount = 1; + byteCount = 1; if ((utf8[0] & 0xE0) == 0xC0) { byteCount = 2; } else if ((utf8[0] & 0xF0) == 0xE0) { @@ -2073,14 +2205,14 @@ static drflac_result drflac__read_utf8_coded_number(drflac_bs* bs, drflac_uint64 byteCount = 7; } else { *pNumberOut = 0; - return DRFLAC_CRC_MISMATCH; // Bad UTF-8 encoding. + return DRFLAC_CRC_MISMATCH; /* Bad UTF-8 encoding. */ } - // Read extra bytes. + /* Read extra bytes. */ drflac_assert(byteCount > 1); - drflac_uint64 result = (drflac_uint64)(utf8[0] & (0xFF >> (byteCount + 1))); - for (int i = 1; i < byteCount; ++i) { + result = (drflac_uint64)(utf8[0] & (0xFF >> (byteCount + 1))); + for (i = 1; i < byteCount; ++i) { if (!drflac__read_uint8(bs, 8, utf8 + i)) { *pNumberOut = 0; return DRFLAC_END_OF_STREAM; @@ -2097,20 +2229,21 @@ static drflac_result drflac__read_utf8_coded_number(drflac_bs* bs, drflac_uint64 +/* +The next two functions are responsible for calculating the prediction. -// The next two functions are responsible for calculating the prediction. -// -// When the bits per sample is >16 we need to use 64-bit integer arithmetic because otherwise we'll run out of precision. It's -// safe to assume this will be slower on 32-bit platforms so we use a more optimal solution when the bits per sample is <=16. +When the bits per sample is >16 we need to use 64-bit integer arithmetic because otherwise we'll run out of precision. It's +safe to assume this will be slower on 32-bit platforms so we use a more optimal solution when the bits per sample is <=16. +*/ static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_32(drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) { - drflac_assert(order <= 32); - - // 32-bit version. - - // VC++ optimizes this to a single jmp. I've not yet verified this for other compilers. drflac_int32 prediction = 0; + drflac_assert(order <= 32); + + /* 32-bit version. */ + + /* VC++ optimizes this to a single jmp. I've not yet verified this for other compilers. */ switch (order) { case 32: prediction += coefficients[31] * pDecodedSamples[-32]; @@ -2152,13 +2285,14 @@ static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_32(drflac_uint32 static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_64(drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) { + drflac_int64 prediction; + drflac_assert(order <= 32); - // 64-bit version. + /* 64-bit version. */ - // This method is faster on the 32-bit build when compiling with VC++. See note below. + /* This method is faster on the 32-bit build when compiling with VC++. See note below. */ #ifndef DRFLAC_64BIT - drflac_int64 prediction; if (order == 8) { prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; @@ -2275,18 +2409,21 @@ static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_64(drflac_uint32 } else { + int j; + prediction = 0; - for (int j = 0; j < (int)order; ++j) { + for (j = 0; j < (int)order; ++j) { prediction += coefficients[j] * (drflac_int64)pDecodedSamples[-j-1]; } } #endif - // VC++ optimizes this to a single jmp instruction, but only the 64-bit build. The 32-bit build generates less efficient code for some - // reason. The ugly version above is faster so we'll just switch between the two depending on the target platform. + /* + VC++ optimizes this to a single jmp instruction, but only the 64-bit build. The 32-bit build generates less efficient code for some + reason. The ugly version above is faster so we'll just switch between the two depending on the target platform. + */ #ifdef DRFLAC_64BIT - drflac_int64 prediction = 0; - + prediction = 0; switch (order) { case 32: prediction += coefficients[31] * (drflac_int64)pDecodedSamples[-32]; @@ -2329,13 +2466,13 @@ static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_64(drflac_uint32 static DRFLAC_INLINE void drflac__calculate_prediction_64_x4(drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, const drflac_uint32 riceParamParts[4], drflac_int32* pDecodedSamples) { - drflac_assert(order <= 32); - drflac_int64 prediction0 = 0; drflac_int64 prediction1 = 0; drflac_int64 prediction2 = 0; drflac_int64 prediction3 = 0; + drflac_assert(order <= 32); + switch (order) { case 32: @@ -2523,10 +2660,10 @@ static DRFLAC_INLINE void drflac__calculate_prediction_64_x4(drflac_uint32 order #if defined(DRFLAC_SUPPORT_SSE41) static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_64__sse41(drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) { - drflac_assert(order <= 32); - __m128i prediction = _mm_setzero_si128(); + drflac_assert(order <= 32); + switch (order) { case 32: @@ -2570,11 +2707,11 @@ static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_64__sse41(drflac_ static DRFLAC_INLINE void drflac__calculate_prediction_64_x2__sse41(drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, const drflac_uint32 riceParamParts[4], drflac_int32* pDecodedSamples) { - drflac_assert(order <= 32); - __m128i prediction = _mm_setzero_si128(); drflac_int64 predictions[2] = {0, 0}; + drflac_assert(order <= 32); + switch (order) { case 32: prediction = _mm_add_epi64(prediction, _mm_mul_epi32(_mm_set_epi32(0, coefficients[31], 0, coefficients[31]), _mm_set_epi32(0, pDecodedSamples[-31], 0, pDecodedSamples[-32]))); @@ -2634,9 +2771,9 @@ static DRFLAC_INLINE __m128i drflac__mm_not_si128(__m128i a) static DRFLAC_INLINE __m128i drflac__mm_slide1_epi32(__m128i a, __m128i b) { - // a3a2a1a0/b3b2b1b0 -> a2a1a0b3 + /* a3a2a1a0/b3b2b1b0 -> a2a1a0b3 */ - // Result = a2a1a0b3 + /* Result = a2a1a0b3 */ __m128i b3a3b2a2 = _mm_unpackhi_epi32(a, b); __m128i a2b3a2b3 = _mm_shuffle_epi32(b3a3b2a2, _MM_SHUFFLE(0, 3, 0, 3)); __m128i a1a2a0b3 = _mm_unpacklo_epi32(a2b3a2b3, a); @@ -2646,7 +2783,7 @@ static DRFLAC_INLINE __m128i drflac__mm_slide1_epi32(__m128i a, __m128i b) static DRFLAC_INLINE __m128i drflac__mm_slide2_epi32(__m128i a, __m128i b) { - // Result = a1a0b3b2 + /* Result = a1a0b3b2 */ __m128i b1b0b3b2 = _mm_shuffle_epi32(b, _MM_SHUFFLE(1, 0, 3, 2)); __m128i a1b3a0b2 = _mm_unpacklo_epi32(b1b0b3b2, a); __m128i a1a0b3b2 = _mm_shuffle_epi32(a1b3a0b2, _MM_SHUFFLE(3, 1, 2, 0)); @@ -2655,7 +2792,7 @@ static DRFLAC_INLINE __m128i drflac__mm_slide2_epi32(__m128i a, __m128i b) static DRFLAC_INLINE __m128i drflac__mm_slide3_epi32(__m128i a, __m128i b) { - // Result = a0b3b2b1 + /* Result = a0b3b2b1 */ __m128i b1a1b0a0 = _mm_unpacklo_epi32(a, b); __m128i a0b1a0b1 = _mm_shuffle_epi32(b1a1b0a0, _MM_SHUFFLE(0, 3, 0, 3)); __m128i b3a0b2b1 = _mm_unpackhi_epi32(a0b1a0b1, b); @@ -2667,16 +2804,21 @@ static DRFLAC_INLINE void drflac__calculate_prediction_32_x4__sse41(drflac_uint3 { drflac_assert(order <= 32); - // I don't think this is as efficient as it could be. More work needs to be done on this. + /* I don't think this is as efficient as it could be. More work needs to be done on this. */ if (order > 0) { + drflac_int32 predictions[4]; + drflac_uint32 riceParamParts[4]; + __m128i s_09_10_11_12 = _mm_loadu_si128((const __m128i*)(pDecodedSamples - 12)); __m128i s_05_06_07_08 = _mm_loadu_si128((const __m128i*)(pDecodedSamples - 8)); __m128i s_01_02_03_04 = _mm_loadu_si128((const __m128i*)(pDecodedSamples - 4)); __m128i prediction = _mm_setzero_si128(); - // The idea with this switch is to do do a single jump based on the value of "order". In my test library, "order" is never larger than 12, so - // I have decided to do a less optimal solution in the order > 12 case. + /* + The idea with this switch is to do do a single jump based on the value of "order". In my test library, "order" is never larger than 12, so + I have decided to do a less optimal, but simpler solution in the order > 12 case. + */ switch (order) { case 32: prediction = _mm_add_epi32(prediction, _mm_mullo_epi32(coefficients128[31], _mm_loadu_si128((const __m128i*)(pDecodedSamples - 32)))); @@ -2708,16 +2850,13 @@ static DRFLAC_INLINE void drflac__calculate_prediction_32_x4__sse41(drflac_uint3 case 7: prediction = _mm_add_epi32(prediction, _mm_mullo_epi32(coefficients128[ 6], drflac__mm_slide3_epi32(s_01_02_03_04, s_05_06_07_08))); case 6: prediction = _mm_add_epi32(prediction, _mm_mullo_epi32(coefficients128[ 5], drflac__mm_slide2_epi32(s_01_02_03_04, s_05_06_07_08))); case 5: prediction = _mm_add_epi32(prediction, _mm_mullo_epi32(coefficients128[ 4], drflac__mm_slide1_epi32(s_01_02_03_04, s_05_06_07_08))); - case 4: prediction = _mm_add_epi32(prediction, _mm_mullo_epi32(coefficients128[ 3], s_01_02_03_04)); order = 3; // <-- Don't forget to set order to 3 here! + case 4: prediction = _mm_add_epi32(prediction, _mm_mullo_epi32(coefficients128[ 3], s_01_02_03_04)); order = 3; /* <-- Don't forget to set order to 3 here! */ case 3: prediction = _mm_add_epi32(prediction, _mm_mullo_epi32(coefficients128[ 2], drflac__mm_slide3_epi32(_mm_setzero_si128(), s_01_02_03_04))); case 2: prediction = _mm_add_epi32(prediction, _mm_mullo_epi32(coefficients128[ 1], drflac__mm_slide2_epi32(_mm_setzero_si128(), s_01_02_03_04))); case 1: prediction = _mm_add_epi32(prediction, _mm_mullo_epi32(coefficients128[ 0], drflac__mm_slide1_epi32(_mm_setzero_si128(), s_01_02_03_04))); } - drflac_int32 predictions[4]; _mm_storeu_si128((__m128i*)predictions, prediction); - - drflac_uint32 riceParamParts[4]; _mm_storeu_si128((__m128i*)riceParamParts, riceParamParts128); predictions[0] = riceParamParts[0] + (predictions[0] >> shift); @@ -2757,15 +2896,19 @@ static DRFLAC_INLINE void drflac__calculate_prediction_32_x4__sse41(drflac_uint3 #endif #if 0 -// Reference implementation for reading and decoding samples with residual. This is intentionally left unoptimized for the -// sake of readability and should only be used as a reference. +/* +Reference implementation for reading and decoding samples with residual. This is intentionally left unoptimized for the +sake of readability and should only be used as a reference. +*/ static drflac_bool32 drflac__decode_samples_with_residual__rice__reference(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { + drflac_uint32 i; + drflac_assert(bs != NULL); drflac_assert(count > 0); drflac_assert(pSamplesOut != NULL); - for (drflac_uint32 i = 0; i < count; ++i) { + for (i = 0; i < count; ++i) { drflac_uint32 zeroCounter = 0; for (;;) { drflac_uint8 bit; @@ -2812,6 +2955,8 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__reference(drfla static drflac_bool32 drflac__read_rice_parts__reference(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut) { drflac_uint32 zeroCounter = 0; + drflac_uint32 decodedRice; + for (;;) { drflac_uint8 bit; if (!drflac__read_uint8(bs, 1, &bit)) { @@ -2825,7 +2970,6 @@ static drflac_bool32 drflac__read_rice_parts__reference(drflac_bs* bs, drflac_ui } } - drflac_uint32 decodedRice; if (riceParam > 0) { if (!drflac__read_uint32(bs, riceParam, &decodedRice)) { return DRFLAC_FALSE; @@ -2843,11 +2987,17 @@ static drflac_bool32 drflac__read_rice_parts__reference(drflac_bs* bs, drflac_ui #if 0 static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut) { - drflac_assert(riceParam > 0); // <-- riceParam should never be 0. drflac__read_rice_parts__param_equals_zero() should be used instead for this case. + drflac_cache_t riceParamMask; + drflac_uint32 zeroCounter; + drflac_uint32 setBitOffsetPlus1; + drflac_uint32 riceParamPart; + drflac_uint32 riceLength; - drflac_cache_t riceParamMask = DRFLAC_CACHE_L1_SELECTION_MASK(riceParam); + drflac_assert(riceParam > 0); /* <-- riceParam should never be 0. drflac__read_rice_parts__param_equals_zero() should be used instead for this case. */ - drflac_uint32 zeroCounter = 0; + riceParamMask = DRFLAC_CACHE_L1_SELECTION_MASK(riceParam); + + zeroCounter = 0; while (bs->cache == 0) { zeroCounter += (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs); if (!drflac__reload_cache(bs)) { @@ -2855,25 +3005,26 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts(drflac_bs* bs, drflac } } - drflac_uint32 setBitOffsetPlus1 = drflac__clz(bs->cache); + setBitOffsetPlus1 = drflac__clz(bs->cache); zeroCounter += setBitOffsetPlus1; setBitOffsetPlus1 += 1; - - drflac_uint32 riceParamPart; - drflac_uint32 riceLength = setBitOffsetPlus1 + riceParam; + riceLength = setBitOffsetPlus1 + riceParam; if (riceLength < DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { riceParamPart = (drflac_uint32)((bs->cache & (riceParamMask >> setBitOffsetPlus1)) >> DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceLength)); bs->consumedBits += riceLength; bs->cache <<= riceLength; } else { - bs->consumedBits += riceLength; - bs->cache <<= setBitOffsetPlus1 & (DRFLAC_CACHE_L1_SIZE_BITS(bs)-1); // <-- Equivalent to "if (setBitOffsetPlus1 < DRFLAC_CACHE_L1_SIZE_BITS(bs)) { bs->cache <<= setBitOffsetPlus1; }" + drflac_uint32 bitCountLo; + drflac_cache_t resultHi; - // It straddles the cached data. It will never cover more than the next chunk. We just read the number in two parts and combine them. - drflac_uint32 bitCountLo = bs->consumedBits - DRFLAC_CACHE_L1_SIZE_BITS(bs); - drflac_cache_t resultHi = DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, riceParam); // <-- Use DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE() if ever this function allows riceParam=0. + bs->consumedBits += riceLength; + bs->cache <<= setBitOffsetPlus1 & (DRFLAC_CACHE_L1_SIZE_BITS(bs)-1); /* <-- Equivalent to "if (setBitOffsetPlus1 < DRFLAC_CACHE_L1_SIZE_BITS(bs)) { bs->cache <<= setBitOffsetPlus1; }" */ + + /* It straddles the cached data. It will never cover more than the next chunk. We just read the number in two parts and combine them. */ + bitCountLo = bs->consumedBits - DRFLAC_CACHE_L1_SIZE_BITS(bs); + resultHi = DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, riceParam); /* <-- Use DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE() if ever this function allows riceParam=0. */ if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { #ifndef DR_FLAC_NO_CRC @@ -2885,7 +3036,7 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts(drflac_bs* bs, drflac bs->crc16Cache = bs->cache; #endif } else { - // Slow path. We need to fetch more data from the client. + /* Slow path. We need to fetch more data from the client. */ if (!drflac__reload_cache(bs)) { return DRFLAC_FALSE; } @@ -2907,44 +3058,54 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts(drflac_bs* bs, drflac static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts_x1(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut) { drflac_uint32 riceParamPlus1 = riceParam + 1; - //drflac_cache_t riceParamPlus1Mask = DRFLAC_CACHE_L1_SELECTION_MASK(riceParamPlus1); + /*drflac_cache_t riceParamPlus1Mask = DRFLAC_CACHE_L1_SELECTION_MASK(riceParamPlus1);*/ drflac_uint32 riceParamPlus1Shift = DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceParamPlus1); drflac_uint32 riceParamPlus1MaxConsumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceParamPlus1; - // The idea here is to use local variables for the cache in an attempt to encourage the compiler to store them in registers. I have - // no idea how this will work in practice... + /* + The idea here is to use local variables for the cache in an attempt to encourage the compiler to store them in registers. I have + no idea how this will work in practice... + */ drflac_cache_t bs_cache = bs->cache; drflac_uint32 bs_consumedBits = bs->consumedBits; - // The first thing to do is find the first unset bit. Most likely a bit will be set in the current cache line. + /* The first thing to do is find the first unset bit. Most likely a bit will be set in the current cache line. */ drflac_uint32 lzcount = drflac__clz(bs_cache); if (lzcount < sizeof(bs_cache)*8) { pZeroCounterOut[0] = lzcount; - // It is most likely that the riceParam part (which comes after the zero counter) is also on this cache line. When extracting - // this, we include the set bit from the unary coded part because it simplifies cache management. This bit will be handled - // outside of this function at a higher level. + /* + It is most likely that the riceParam part (which comes after the zero counter) is also on this cache line. When extracting + this, we include the set bit from the unary coded part because it simplifies cache management. This bit will be handled + outside of this function at a higher level. + */ extract_rice_param_part: bs_cache <<= lzcount; bs_consumedBits += lzcount; if (bs_consumedBits <= riceParamPlus1MaxConsumedBits) { - // Getting here means the rice parameter part is wholly contained within the current cache line. + /* Getting here means the rice parameter part is wholly contained within the current cache line. */ pRiceParamPartOut[0] = (drflac_uint32)(bs_cache >> riceParamPlus1Shift); bs_cache <<= riceParamPlus1; bs_consumedBits += riceParamPlus1; } else { - // Getting here means the rice parameter part straddles the cache line. We need to read from the tail of the current cache - // line, reload the cache, and then combine it with the head of the next cache line. + drflac_uint32 riceParamPartHi; + drflac_uint32 riceParamPartLo; + drflac_uint32 riceParamPartLoBitCount; - // Grab the high part of the rice parameter part. - drflac_uint32 riceParamPartHi = (drflac_uint32)(bs_cache >> riceParamPlus1Shift); + /* + Getting here means the rice parameter part straddles the cache line. We need to read from the tail of the current cache + line, reload the cache, and then combine it with the head of the next cache line. + */ - // Before reloading the cache we need to grab the size in bits of the low part. - drflac_uint32 riceParamPartLoBitCount = bs_consumedBits - riceParamPlus1MaxConsumedBits; + /* Grab the high part of the rice parameter part. */ + riceParamPartHi = (drflac_uint32)(bs_cache >> riceParamPlus1Shift); + + /* Before reloading the cache we need to grab the size in bits of the low part. */ + riceParamPartLoBitCount = bs_consumedBits - riceParamPlus1MaxConsumedBits; drflac_assert(riceParamPartLoBitCount > 0 && riceParamPartLoBitCount < 32); - // Now reload the cache. + /* Now reload the cache. */ if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { #ifndef DR_FLAC_NO_CRC drflac__update_crc16(bs); @@ -2955,7 +3116,7 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts_x1(drflac_bs* bs, drf bs->crc16Cache = bs_cache; #endif } else { - // Slow path. We need to fetch more data from the client. + /* Slow path. We need to fetch more data from the client. */ if (!drflac__reload_cache(bs)) { return DRFLAC_FALSE; } @@ -2964,15 +3125,17 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts_x1(drflac_bs* bs, drf bs_consumedBits = bs->consumedBits + riceParamPartLoBitCount; } - // We should now have enough information to construct the rice parameter part. - drflac_uint32 riceParamPartLo = (drflac_uint32)(bs_cache >> (DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceParamPartLoBitCount))); + /* We should now have enough information to construct the rice parameter part. */ + riceParamPartLo = (drflac_uint32)(bs_cache >> (DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceParamPartLoBitCount))); pRiceParamPartOut[0] = riceParamPartHi | riceParamPartLo; bs_cache <<= riceParamPartLoBitCount; } } else { - // Getting here means there are no bits set on the cache line. This is a less optimal case because we just wasted a call - // to drflac__clz() and we need to reload the cache. + /* + Getting here means there are no bits set on the cache line. This is a less optimal case because we just wasted a call + to drflac__clz() and we need to reload the cache. + */ drflac_uint32 zeroCounter = (drflac_uint32)(DRFLAC_CACHE_L1_SIZE_BITS(bs) - bs_consumedBits); for (;;) { if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { @@ -2985,7 +3148,7 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts_x1(drflac_bs* bs, drf bs->crc16Cache = bs_cache; #endif } else { - // Slow path. We need to fetch more data from the client. + /* Slow path. We need to fetch more data from the client. */ if (!drflac__reload_cache(bs)) { return DRFLAC_FALSE; } @@ -3006,7 +3169,7 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts_x1(drflac_bs* bs, drf goto extract_rice_param_part; } - // Make sure the cache is restored at the end of it all. + /* Make sure the cache is restored at the end of it all. */ bs->cache = bs_cache; bs->consumedBits = bs_consumedBits; @@ -3016,46 +3179,59 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts_x1(drflac_bs* bs, drf static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts_x4(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut) { drflac_uint32 riceParamPlus1 = riceParam + 1; - //drflac_cache_t riceParamPlus1Mask = DRFLAC_CACHE_L1_SELECTION_MASK(riceParamPlus1); + /*drflac_cache_t riceParamPlus1Mask = DRFLAC_CACHE_L1_SELECTION_MASK(riceParamPlus1);*/ drflac_uint32 riceParamPlus1Shift = DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceParamPlus1); drflac_uint32 riceParamPlus1MaxConsumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceParamPlus1; - // The idea here is to use local variables for the cache in an attempt to encourage the compiler to store them in registers. I have - // no idea how this will work in practice... + /* + The idea here is to use local variables for the cache in an attempt to encourage the compiler to store them in registers. I have + no idea how this will work in practice... + */ drflac_cache_t bs_cache = bs->cache; drflac_uint32 bs_consumedBits = bs->consumedBits; - // What this is doing is trying to efficiently extract 4 rice parts at a time, the idea being that we can exploit certain properties - // to our advantage to make things more efficient. - for (int i = 0; i < 4; ++i) { - // The first thing to do is find the first unset bit. Most likely a bit will be set in the current cache line. + /* + What this is doing is trying to efficiently extract 4 rice parts at a time, the idea being that we can exploit certain properties + to our advantage to make things more efficient. + */ + int i; + for (i = 0; i < 4; ++i) { + /* The first thing to do is find the first unset bit. Most likely a bit will be set in the current cache line. */ drflac_uint32 lzcount = drflac__clz(bs_cache); if (lzcount < sizeof(bs_cache)*8) { pZeroCounterOut[i] = lzcount; - // It is most likely that the riceParam part (which comes after the zero counter) is also on this cache line. When extracting - // this, we include the set bit from the unary coded part because it simplifies cache management. This bit will be handled - // outside of this function at a higher level. + /* + It is most likely that the riceParam part (which comes after the zero counter) is also on this cache line. When extracting + this, we include the set bit from the unary coded part because it simplifies cache management. This bit will be handled + outside of this function at a higher level. + */ extract_rice_param_part: bs_cache <<= lzcount; bs_consumedBits += lzcount; if (bs_consumedBits <= riceParamPlus1MaxConsumedBits) { - // Getting here means the rice parameter part is wholly contained within the current cache line. + /* Getting here means the rice parameter part is wholly contained within the current cache line. */ pRiceParamPartOut[i] = (drflac_uint32)(bs_cache >> riceParamPlus1Shift); bs_cache <<= riceParamPlus1; bs_consumedBits += riceParamPlus1; } else { - // Getting here means the rice parameter part straddles the cache line. We need to read from the tail of the current cache - // line, reload the cache, and then combine it with the head of the next cache line. + drflac_uint32 riceParamPartHi; + drflac_uint32 riceParamPartLo; + drflac_uint32 riceParamPartLoBitCount; - // Grab the high part of the rice parameter part. - drflac_uint32 riceParamPartHi = (drflac_uint32)(bs_cache >> riceParamPlus1Shift); + /* + Getting here means the rice parameter part straddles the cache line. We need to read from the tail of the current cache + line, reload the cache, and then combine it with the head of the next cache line. + */ - // Before reloading the cache we need to grab the size in bits of the low part. - drflac_uint32 riceParamPartLoBitCount = bs_consumedBits - riceParamPlus1MaxConsumedBits; + /* Grab the high part of the rice parameter part. */ + riceParamPartHi = (drflac_uint32)(bs_cache >> riceParamPlus1Shift); + + /* Before reloading the cache we need to grab the size in bits of the low part. */ + riceParamPartLoBitCount = bs_consumedBits - riceParamPlus1MaxConsumedBits; - // Now reload the cache. + /* Now reload the cache. */ if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { #ifndef DR_FLAC_NO_CRC drflac__update_crc16(bs); @@ -3066,7 +3242,7 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts_x4(drflac_bs* bs, drf bs->crc16Cache = bs_cache; #endif } else { - // Slow path. We need to fetch more data from the client. + /* Slow path. We need to fetch more data from the client. */ if (!drflac__reload_cache(bs)) { return DRFLAC_FALSE; } @@ -3075,15 +3251,17 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts_x4(drflac_bs* bs, drf bs_consumedBits = bs->consumedBits + riceParamPartLoBitCount; } - // We should now have enough information to construct the rice parameter part. - drflac_uint32 riceParamPartLo = (drflac_uint32)(bs_cache >> (DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceParamPartLoBitCount))); + /* We should now have enough information to construct the rice parameter part. */ + riceParamPartLo = (drflac_uint32)(bs_cache >> (DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceParamPartLoBitCount))); pRiceParamPartOut[i] = riceParamPartHi | riceParamPartLo; bs_cache <<= riceParamPartLoBitCount; } } else { - // Getting here means there are no bits set on the cache line. This is a less optimal case because we just wasted a call - // to drflac__clz() and we need to reload the cache. + /* + Getting here means there are no bits set on the cache line. This is a less optimal case because we just wasted a call + to drflac__clz() and we need to reload the cache. + */ drflac_uint32 zeroCounter = (drflac_uint32)(DRFLAC_CACHE_L1_SIZE_BITS(bs) - bs_consumedBits); for (;;) { if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { @@ -3096,7 +3274,7 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts_x4(drflac_bs* bs, drf bs->crc16Cache = bs_cache; #endif } else { - // Slow path. We need to fetch more data from the client. + /* Slow path. We need to fetch more data from the client. */ if (!drflac__reload_cache(bs)) { return DRFLAC_FALSE; } @@ -3118,7 +3296,7 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts_x4(drflac_bs* bs, drf } } - // Make sure the cache is restored at the end of it all. + /* Make sure the cache is restored at the end of it all. */ bs->cache = bs_cache; bs->consumedBits = bs_consumedBits; @@ -3130,34 +3308,40 @@ static DRFLAC_INLINE drflac_bool32 drflac__seek_rice_parts(drflac_bs* bs, drflac drflac_uint32 riceParamPlus1 = riceParam + 1; drflac_uint32 riceParamPlus1MaxConsumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceParamPlus1; - // The idea here is to use local variables for the cache in an attempt to encourage the compiler to store them in registers. I have - // no idea how this will work in practice... + /* + The idea here is to use local variables for the cache in an attempt to encourage the compiler to store them in registers. I have + no idea how this will work in practice... + */ drflac_cache_t bs_cache = bs->cache; drflac_uint32 bs_consumedBits = bs->consumedBits; - // The first thing to do is find the first unset bit. Most likely a bit will be set in the current cache line. + /* The first thing to do is find the first unset bit. Most likely a bit will be set in the current cache line. */ drflac_uint32 lzcount = drflac__clz(bs_cache); if (lzcount < sizeof(bs_cache)*8) { - // It is most likely that the riceParam part (which comes after the zero counter) is also on this cache line. When extracting - // this, we include the set bit from the unary coded part because it simplifies cache management. This bit will be handled - // outside of this function at a higher level. + /* + It is most likely that the riceParam part (which comes after the zero counter) is also on this cache line. When extracting + this, we include the set bit from the unary coded part because it simplifies cache management. This bit will be handled + outside of this function at a higher level. + */ extract_rice_param_part: bs_cache <<= lzcount; bs_consumedBits += lzcount; if (bs_consumedBits <= riceParamPlus1MaxConsumedBits) { - // Getting here means the rice parameter part is wholly contained within the current cache line. + /* Getting here means the rice parameter part is wholly contained within the current cache line. */ bs_cache <<= riceParamPlus1; bs_consumedBits += riceParamPlus1; } else { - // Getting here means the rice parameter part straddles the cache line. We need to read from the tail of the current cache - // line, reload the cache, and then combine it with the head of the next cache line. + /* + Getting here means the rice parameter part straddles the cache line. We need to read from the tail of the current cache + line, reload the cache, and then combine it with the head of the next cache line. + */ - // Before reloading the cache we need to grab the size in bits of the low part. + /* Before reloading the cache we need to grab the size in bits of the low part. */ drflac_uint32 riceParamPartLoBitCount = bs_consumedBits - riceParamPlus1MaxConsumedBits; drflac_assert(riceParamPartLoBitCount > 0 && riceParamPartLoBitCount < 32); - // Now reload the cache. + /* Now reload the cache. */ if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { #ifndef DR_FLAC_NO_CRC drflac__update_crc16(bs); @@ -3168,7 +3352,7 @@ static DRFLAC_INLINE drflac_bool32 drflac__seek_rice_parts(drflac_bs* bs, drflac bs->crc16Cache = bs_cache; #endif } else { - // Slow path. We need to fetch more data from the client. + /* Slow path. We need to fetch more data from the client. */ if (!drflac__reload_cache(bs)) { return DRFLAC_FALSE; } @@ -3180,8 +3364,10 @@ static DRFLAC_INLINE drflac_bool32 drflac__seek_rice_parts(drflac_bs* bs, drflac bs_cache <<= riceParamPartLoBitCount; } } else { - // Getting here means there are no bits set on the cache line. This is a less optimal case because we just wasted a call - // to drflac__clz() and we need to reload the cache. + /* + Getting here means there are no bits set on the cache line. This is a less optimal case because we just wasted a call + to drflac__clz() and we need to reload the cache. + */ for (;;) { if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { #ifndef DR_FLAC_NO_CRC @@ -3193,7 +3379,7 @@ static DRFLAC_INLINE drflac_bool32 drflac__seek_rice_parts(drflac_bs* bs, drflac bs->crc16Cache = bs_cache; #endif } else { - // Slow path. We need to fetch more data from the client. + /* Slow path. We need to fetch more data from the client. */ if (!drflac__reload_cache(bs)) { return DRFLAC_FALSE; } @@ -3211,7 +3397,7 @@ static DRFLAC_INLINE drflac_bool32 drflac__seek_rice_parts(drflac_bs* bs, drflac goto extract_rice_param_part; } - // Make sure the cache is restored at the end of it all. + /* Make sure the cache is restored at the end of it all. */ bs->cache = bs_cache; bs->consumedBits = bs_consumedBits; @@ -3221,12 +3407,7 @@ static DRFLAC_INLINE drflac_bool32 drflac__seek_rice_parts(drflac_bs* bs, drflac static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { - drflac_assert(bs != NULL); - drflac_assert(count > 0); - drflac_assert(pSamplesOut != NULL); - drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; - drflac_uint32 zeroCountPart0; drflac_uint32 zeroCountPart1; drflac_uint32 zeroCountPart2; @@ -3235,13 +3416,23 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_b drflac_uint32 riceParamPart1; drflac_uint32 riceParamPart2; drflac_uint32 riceParamPart3; - drflac_uint32 riceParamMask = ~((~0UL) << riceParam); - const drflac_int32* pSamplesOutEnd = pSamplesOut + ((count >> 2) << 2); + drflac_uint32 riceParamMask; + const drflac_int32* pSamplesOutEnd; + drflac_uint32 i; + + drflac_assert(bs != NULL); + drflac_assert(count > 0); + drflac_assert(pSamplesOut != NULL); + + riceParamMask = ~((~0UL) << riceParam); + pSamplesOutEnd = pSamplesOut + ((count >> 2) << 2); if (bitsPerSample >= 24) { while (pSamplesOut < pSamplesOutEnd) { - // Rice extraction. It's faster to do this one at a time against local variables than it is to use the x4 version - // against an array. Not sure why, but perhaps it's making more efficient use of registers? + /* + Rice extraction. It's faster to do this one at a time against local variables than it is to use the x4 version + against an array. Not sure why, but perhaps it's making more efficient use of registers? + */ if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0) || !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart1, &riceParamPart1) || !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart2, &riceParamPart2) || @@ -3304,22 +3495,20 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_b } } - - - drflac_uint32 i = ((count >> 2) << 2); + i = ((count >> 2) << 2); while (i < count) { - // Rice extraction. + /* Rice extraction. */ if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0)) { return DRFLAC_FALSE; } - // Rice reconstruction. + /* Rice reconstruction. */ riceParamPart0 &= riceParamMask; riceParamPart0 |= (zeroCountPart0 << riceParam); riceParamPart0 = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01]; - //riceParamPart0 = (riceParamPart0 >> 1) ^ (~(riceParamPart0 & 0x01) + 1); + /*riceParamPart0 = (riceParamPart0 >> 1) ^ (~(riceParamPart0 & 0x01) + 1);*/ - // Sample reconstruction. + /* Sample reconstruction. */ if (bitsPerSample >= 24) { pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 0); } else { @@ -3336,14 +3525,10 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_b #if defined(DRFLAC_SUPPORT_SSE41) static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) { - drflac_assert(bs != NULL); - drflac_assert(count > 0); - drflac_assert(pSamplesOut != NULL); - static drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; - //drflac_uint32 zeroCountParts[4]; - //drflac_uint32 riceParamParts[4]; + /*drflac_uint32 zeroCountParts[4];*/ + /*drflac_uint32 riceParamParts[4];*/ drflac_uint32 zeroCountParts0; drflac_uint32 zeroCountParts1; @@ -3353,16 +3538,29 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41(drflac_bs drflac_uint32 riceParamParts1; drflac_uint32 riceParamParts2; drflac_uint32 riceParamParts3; + drflac_uint32 riceParamMask; + const drflac_int32* pSamplesOutEnd; + __m128i riceParamMask128; + __m128i one; + drflac_uint32 i; - drflac_uint32 riceParamMask = ~((~0UL) << riceParam); - __m128i riceParamMask128 = _mm_set1_epi32(riceParamMask); - __m128i one = _mm_set1_epi32(0x01); + drflac_assert(bs != NULL); + drflac_assert(count > 0); + drflac_assert(pSamplesOut != NULL); - const drflac_int32* pSamplesOutEnd = pSamplesOut + ((count >> 2) << 2); + riceParamMask = ~((~0UL) << riceParam); + riceParamMask128 = _mm_set1_epi32(riceParamMask); + one = _mm_set1_epi32(0x01); + + pSamplesOutEnd = pSamplesOut + ((count >> 2) << 2); if (bitsPerSample >= 24) { while (pSamplesOut < pSamplesOutEnd) { - // Rice extraction. + __m128i zeroCountPart128; + __m128i riceParamPart128; + drflac_uint32 riceParamParts[4]; + + /* Rice extraction. */ if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0) || !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts1, &riceParamParts1) || !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts2, &riceParamParts2) || @@ -3370,19 +3568,18 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41(drflac_bs return DRFLAC_FALSE; } - __m128i zeroCountPart128 = _mm_set_epi32(zeroCountParts3, zeroCountParts2, zeroCountParts1, zeroCountParts0); - __m128i riceParamPart128 = _mm_set_epi32(riceParamParts3, riceParamParts2, riceParamParts1, riceParamParts0); + zeroCountPart128 = _mm_set_epi32(zeroCountParts3, zeroCountParts2, zeroCountParts1, zeroCountParts0); + riceParamPart128 = _mm_set_epi32(riceParamParts3, riceParamParts2, riceParamParts1, riceParamParts0); riceParamPart128 = _mm_and_si128(riceParamPart128, riceParamMask128); riceParamPart128 = _mm_or_si128(riceParamPart128, _mm_slli_epi32(zeroCountPart128, riceParam)); - riceParamPart128 = _mm_xor_si128(_mm_srli_epi32(riceParamPart128, 1), _mm_mullo_epi32(_mm_and_si128(riceParamPart128, one), _mm_set1_epi32(0xFFFFFFFF))); // <-- Only supported from SSE4.1 - //riceParamPart128 = _mm_xor_si128(_mm_srli_epi32(riceParamPart128, 1), _mm_add_epi32(drflac__mm_not_si128(_mm_and_si128(riceParamPart128, one)), one)); // <-- SSE2 compatible + riceParamPart128 = _mm_xor_si128(_mm_srli_epi32(riceParamPart128, 1), _mm_mullo_epi32(_mm_and_si128(riceParamPart128, one), _mm_set1_epi32(0xFFFFFFFF))); /* <-- Only supported from SSE4.1 */ + /*riceParamPart128 = _mm_xor_si128(_mm_srli_epi32(riceParamPart128, 1), _mm_add_epi32(drflac__mm_not_si128(_mm_and_si128(riceParamPart128, one)), one));*/ /* <-- SSE2 compatible */ - drflac_uint32 riceParamParts[4]; _mm_storeu_si128((__m128i*)riceParamParts, riceParamPart128); #if defined(DRFLAC_64BIT) - // The scalar implementation seems to be faster on 64-bit in my testing. + /* The scalar implementation seems to be faster on 64-bit in my testing. */ drflac__calculate_prediction_64_x4(order, shift, coefficients, riceParamParts, pSamplesOut); #else pSamplesOut[0] = riceParamParts[0] + drflac__calculate_prediction_64__sse41(order, shift, coefficients, pSamplesOut + 0); @@ -3396,7 +3593,8 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41(drflac_bs } else { drflac_int32 coefficientsUnaligned[32*4 + 4] = {0}; drflac_int32* coefficients128 = (drflac_int32*)(((size_t)coefficientsUnaligned + 15) & ~15); - for (drflac_uint32 i = 0; i < order; ++i) { + + for (i = 0; i < order; ++i) { coefficients128[i*4+0] = coefficients[i]; coefficients128[i*4+1] = coefficients[i]; coefficients128[i*4+2] = coefficients[i]; @@ -3404,7 +3602,11 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41(drflac_bs } while (pSamplesOut < pSamplesOutEnd) { - // Rice extraction. + __m128i zeroCountPart128; + __m128i riceParamPart128; + /*drflac_int32 riceParamParts[4];*/ + + /* Rice extraction. */ #if 1 if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0) || !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts1, &riceParamParts1) || @@ -3413,15 +3615,15 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41(drflac_bs return DRFLAC_FALSE; } - __m128i zeroCountPart128 = _mm_set_epi32(zeroCountParts3, zeroCountParts2, zeroCountParts1, zeroCountParts0); - __m128i riceParamPart128 = _mm_set_epi32(riceParamParts3, riceParamParts2, riceParamParts1, riceParamParts0); + zeroCountPart128 = _mm_set_epi32(zeroCountParts3, zeroCountParts2, zeroCountParts1, zeroCountParts0); + riceParamPart128 = _mm_set_epi32(riceParamParts3, riceParamParts2, riceParamParts1, riceParamParts0); #else if (!drflac__read_rice_parts_x4(bs, riceParam, zeroCountParts, riceParamParts)) { return DRFLAC_FALSE; } - __m128i zeroCountPart128 = _mm_set_epi32(zeroCountParts[3], zeroCountParts[2], zeroCountParts[1], zeroCountParts[0]); - __m128i riceParamPart128 = _mm_set_epi32(riceParamParts[3], riceParamParts[2], riceParamParts[1], riceParamParts[0]); + zeroCountPart128 = _mm_set_epi32(zeroCountParts[3], zeroCountParts[2], zeroCountParts[1], zeroCountParts[0]); + riceParamPart128 = _mm_set_epi32(riceParamParts[3], riceParamParts[2], riceParamParts[1], riceParamParts[0]); #endif riceParamPart128 = _mm_and_si128(riceParamPart128, riceParamMask128); @@ -3431,7 +3633,6 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41(drflac_bs #if 1 drflac__calculate_prediction_32_x4__sse41(order, shift, (const __m128i*)coefficients128, riceParamPart128, pSamplesOut); #else - drflac_int32 riceParamParts[4]; _mm_storeu_si128((__m128i*)riceParamParts, riceParamPart128); pSamplesOut[0] = riceParamParts[0] + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 0); @@ -3445,19 +3646,19 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41(drflac_bs } - drflac_uint32 i = ((count >> 2) << 2); + i = ((count >> 2) << 2); while (i < count) { - // Rice extraction. + /* Rice extraction. */ if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0)) { return DRFLAC_FALSE; } - // Rice reconstruction. + /* Rice reconstruction. */ riceParamParts0 &= riceParamMask; riceParamParts0 |= (zeroCountParts0 << riceParam); riceParamParts0 = (riceParamParts0 >> 1) ^ t[riceParamParts0 & 0x01]; - // Sample reconstruction. + /* Sample reconstruction. */ if (bitsPerSample >= 24) { pSamplesOut[0] = riceParamParts0 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 0); } else { @@ -3480,7 +3681,7 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice(drflac_bs* bs, d } else #endif { - // Scalar fallback. + /* Scalar fallback. */ #if 0 return drflac__decode_samples_with_residual__rice__reference(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut); #else @@ -3489,13 +3690,15 @@ static drflac_bool32 drflac__decode_samples_with_residual__rice(drflac_bs* bs, d } } -// 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. +/* 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 (drflac_uint32 i = 0; i < count; ++i) { + for (i = 0; i < count; ++i) { if (!drflac__seek_rice_parts(bs, riceParam)) { return DRFLAC_FALSE; } @@ -3506,12 +3709,14 @@ static drflac_bool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, drflac_ 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, drflac_int32* pSamplesOut) { + 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(unencodedBitsPerSample <= 31); /* <-- unencodedBitsPerSample is a 5 bit number, so cannot exceed 31. */ drflac_assert(pSamplesOut != NULL); - for (unsigned int i = 0; i < count; ++i) { + for (i = 0; i < count; ++i) { if (unencodedBitsPerSample > 0) { if (!drflac__read_int32(bs, unencodedBitsPerSample, pSamplesOut + i)) { return DRFLAC_FALSE; @@ -3531,46 +3736,52 @@ static drflac_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* } -// 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 residuals will be ignored. The -// and parameters are used to determine how many residual values need to be decoded. +/* +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 residuals will be ignored. The + and 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? + drflac_assert(pDecodedSamples != NULL); /* <-- Should we allow NULL, in which case we just seek past the residual rather than do a full decode? */ - drflac_uint8 residualMethod; 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. + return DRFLAC_FALSE; /* Unknown or unsupported residual coding method. */ } - // Ignore the first values. + /* Ignore the first values. */ pDecodedSamples += order; - - drflac_uint8 partitionOrder; 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. + /* + 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. + /* Validation check. */ if ((blockSize / (1 << partitionOrder)) <= order) { return DRFLAC_FALSE; } - drflac_uint32 samplesInPartition = (blockSize / (1 << partitionOrder)) - order; - drflac_uint32 partitionsRemaining = (1 << partitionOrder); + samplesInPartition = (blockSize / (1 << partitionOrder)) - order; + partitionsRemaining = (1 << partitionOrder); for (;;) { drflac_uint8 riceParam = 0; if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) { @@ -3606,7 +3817,6 @@ static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_ pDecodedSamples += samplesInPartition; - if (partitionsRemaining == 1) { break; } @@ -3621,41 +3831,48 @@ static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_ 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 residuals will be set to 0. The -// and parameters are used to determine how many residual values need to be decoded. +/* +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 residuals will be set to 0. The + and 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); - drflac_uint8 residualMethod; 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. + return DRFLAC_FALSE; /* Unknown or unsupported residual coding method. */ } - drflac_uint8 partitionOrder; 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. + /* + 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. + /* Validation check. */ if ((blockSize / (1 << partitionOrder)) <= order) { return DRFLAC_FALSE; } - drflac_uint32 samplesInPartition = (blockSize / (1 << partitionOrder)) - order; - drflac_uint32 partitionsRemaining = (1 << partitionOrder); + samplesInPartition = (blockSize / (1 << partitionOrder)) - order; + partitionsRemaining = (1 << partitionOrder); for (;;) { drflac_uint8 riceParam = 0; @@ -3705,15 +3922,19 @@ static drflac_bool32 drflac__read_and_seek_residual(drflac_bs* bs, drflac_uint32 static drflac_bool32 drflac__decode_samples__constant(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 bitsPerSample, drflac_int32* pDecodedSamples) { - // Only a single sample needs to be decoded here. + drflac_uint32 i; + + /* Only a single sample needs to be decoded here. */ drflac_int32 sample; if (!drflac__read_int32(bs, bitsPerSample, &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 (drflac_uint32 i = 0; i < blockSize; ++i) { + /* + 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; } @@ -3722,7 +3943,9 @@ static drflac_bool32 drflac__decode_samples__constant(drflac_bs* bs, drflac_uint static drflac_bool32 drflac__decode_samples__verbatim(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 bitsPerSample, drflac_int32* pDecodedSamples) { - for (drflac_uint32 i = 0; i < blockSize; ++i) { + drflac_uint32 i; + + for (i = 0; i < blockSize; ++i) { drflac_int32 sample; if (!drflac__read_int32(bs, bitsPerSample, &sample)) { return DRFLAC_FALSE; @@ -3736,6 +3959,8 @@ static drflac_bool32 drflac__decode_samples__verbatim(drflac_bs* bs, drflac_uint static drflac_bool32 drflac__decode_samples__fixed(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 bitsPerSample, drflac_uint8 lpcOrder, drflac_int32* pDecodedSamples) { + drflac_uint32 i; + static drflac_int32 lpcCoefficientsTable[5][4] = { {0, 0, 0, 0}, {1, 0, 0, 0}, @@ -3744,8 +3969,8 @@ static drflac_bool32 drflac__decode_samples__fixed(drflac_bs* bs, drflac_uint32 {4, -6, 4, -1} }; - // Warm up samples and coefficients. - for (drflac_uint32 i = 0; i < lpcOrder; ++i) { + /* Warm up samples and coefficients. */ + for (i = 0; i < lpcOrder; ++i) { drflac_int32 sample; if (!drflac__read_int32(bs, bitsPerSample, &sample)) { return DRFLAC_FALSE; @@ -3754,7 +3979,6 @@ static drflac_bool32 drflac__decode_samples__fixed(drflac_bs* bs, drflac_uint32 pDecodedSamples[i] = sample; } - if (!drflac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, 0, lpcCoefficientsTable[lpcOrder], pDecodedSamples)) { return DRFLAC_FALSE; } @@ -3765,8 +3989,11 @@ static drflac_bool32 drflac__decode_samples__fixed(drflac_bs* bs, drflac_uint32 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. + /* Warm up samples. */ for (i = 0; i < lpcOrder; ++i) { drflac_int32 sample; if (!drflac__read_int32(bs, bitsPerSample, &sample)) { @@ -3776,23 +4003,18 @@ static drflac_bool32 drflac__decode_samples__lpc(drflac_bs* bs, drflac_uint32 bl pDecodedSamples[i] = sample; } - drflac_uint8 lpcPrecision; if (!drflac__read_uint8(bs, 4, &lpcPrecision)) { return DRFLAC_FALSE; } if (lpcPrecision == 15) { - return DRFLAC_FALSE; // Invalid. + return DRFLAC_FALSE; /* Invalid. */ } lpcPrecision += 1; - - drflac_int8 lpcShift; if (!drflac__read_int8(bs, 5, &lpcShift)) { return DRFLAC_FALSE; } - - drflac_int32 coefficients[32]; drflac_zero_memory(coefficients, sizeof(coefficients)); for (i = 0; i < lpcOrder; ++i) { if (!drflac__read_int32(bs, lpcPrecision, coefficients + i)) { @@ -3810,21 +4032,27 @@ static drflac_bool32 drflac__decode_samples__lpc(drflac_bs* bs, drflac_uint32 bl 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); - 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. - - // Keep looping until we find a valid sync code. + /* 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; } - drflac_uint8 crc8 = 0xCE; // 0xCE = drflac_crc8(0, 0x3FFE, 14); - - drflac_uint8 reserved = 0; if (!drflac__read_uint8(bs, 1, &reserved)) { return DRFLAC_FALSE; } @@ -3833,15 +4061,11 @@ static drflac_bool32 drflac__read_next_flac_frame_header(drflac_bs* bs, drflac_u } crc8 = drflac_crc8(crc8, reserved, 1); - - drflac_uint8 blockingStrategy = 0; if (!drflac__read_uint8(bs, 1, &blockingStrategy)) { return DRFLAC_FALSE; } crc8 = drflac_crc8(crc8, blockingStrategy, 1); - - drflac_uint8 blockSize = 0; if (!drflac__read_uint8(bs, 4, &blockSize)) { return DRFLAC_FALSE; } @@ -3850,15 +4074,11 @@ static drflac_bool32 drflac__read_next_flac_frame_header(drflac_bs* bs, drflac_u } crc8 = drflac_crc8(crc8, blockSize, 4); - - drflac_uint8 sampleRate = 0; if (!drflac__read_uint8(bs, 4, &sampleRate)) { return DRFLAC_FALSE; } crc8 = drflac_crc8(crc8, sampleRate, 4); - - drflac_uint8 channelAssignment = 0; if (!drflac__read_uint8(bs, 4, &channelAssignment)) { return DRFLAC_FALSE; } @@ -3867,8 +4087,6 @@ static drflac_bool32 drflac__read_next_flac_frame_header(drflac_bs* bs, drflac_u } crc8 = drflac_crc8(crc8, channelAssignment, 4); - - drflac_uint8 bitsPerSample = 0; if (!drflac__read_uint8(bs, 3, &bitsPerSample)) { return DRFLAC_FALSE; } @@ -3887,7 +4105,7 @@ static drflac_bool32 drflac__read_next_flac_frame_header(drflac_bs* bs, drflac_u crc8 = drflac_crc8(crc8, reserved, 1); - drflac_bool32 isVariableBlockSize = blockingStrategy == 1; + isVariableBlockSize = blockingStrategy == 1; if (isVariableBlockSize) { drflac_uint64 sampleNumber; drflac_result result = drflac__read_utf8_coded_number(bs, &sampleNumber, &crc8); @@ -3910,7 +4128,7 @@ static drflac_bool32 drflac__read_next_flac_frame_header(drflac_bs* bs, drflac_u continue; } } - header->frameNumber = (drflac_uint32)frameNumber; // <-- Safe cast. + header->frameNumber = (drflac_uint32)frameNumber; /* <-- Safe cast. */ header->sampleNumber = 0; } @@ -3956,7 +4174,7 @@ static drflac_bool32 drflac__read_next_flac_frame_header(drflac_bs* bs, drflac_u crc8 = drflac_crc8(crc8, header->sampleRate, 16); header->sampleRate *= 10; } else { - continue; // Invalid. Assume an invalid block. + continue; /* Invalid. Assume an invalid block. */ } @@ -3973,7 +4191,7 @@ static drflac_bool32 drflac__read_next_flac_frame_header(drflac_bs* bs, drflac_u #ifndef DR_FLAC_NO_CRC if (header->crc8 != crc8) { - continue; // CRC mismatch. Loop back to the top and find the next sync code. + continue; /* CRC mismatch. Loop back to the top and find the next sync code. */ } #endif return DRFLAC_TRUE; @@ -3983,16 +4201,18 @@ static drflac_bool32 drflac__read_next_flac_frame_header(drflac_bs* bs, drflac_u 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. + /* First bit should always be 0. */ if ((header & 0x80) != 0) { return DRFLAC_FALSE; } - int type = (header & 0x7E) >> 1; + type = (header & 0x7E) >> 1; if (type == 0) { pSubframe->subframeType = DRFLAC_SUBFRAME_CONSTANT; } else if (type == 1) { @@ -4017,7 +4237,7 @@ static drflac_bool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe return DRFLAC_FALSE; } - // Wasted bits per sample. + /* Wasted bits per sample. */ pSubframe->wastedBitsPerSample = 0; if ((header & 0x01) == 1) { unsigned int wastedBitsPerSample; @@ -4032,15 +4252,17 @@ static drflac_bool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe static drflac_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex, drflac_int32* pDecodedSamplesOut) { + drflac_subframe* pSubframe; + drflac_assert(bs != NULL); drflac_assert(frame != NULL); - drflac_subframe* pSubframe = frame->subframes + subframeIndex; + 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... + /* Side channels require an extra bit per sample. Took a while to figure that one out... */ pSubframe->bitsPerSample = frame->header.bitsPerSample; if ((frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) { pSubframe->bitsPerSample += 1; @@ -4048,7 +4270,7 @@ static drflac_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, pSubframe->bitsPerSample += 1; } - // Need to handle wasted bits per sample. + /* Need to handle wasted bits per sample. */ if (pSubframe->wastedBitsPerSample >= pSubframe->bitsPerSample) { return DRFLAC_FALSE; } @@ -4085,15 +4307,17 @@ static drflac_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, static drflac_bool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex) { + drflac_subframe* pSubframe; + drflac_assert(bs != NULL); drflac_assert(frame != NULL); - drflac_subframe* pSubframe = frame->subframes + subframeIndex; + 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... + /* Side channels require an extra bit per sample. Took a while to figure that one out... */ pSubframe->bitsPerSample = frame->header.bitsPerSample; if ((frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) { pSubframe->bitsPerSample += 1; @@ -4101,7 +4325,7 @@ static drflac_bool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, i pSubframe->bitsPerSample += 1; } - // Need to handle wasted bits per sample. + /* Need to handle wasted bits per sample. */ if (pSubframe->wastedBitsPerSample >= pSubframe->bitsPerSample) { return DRFLAC_FALSE; } @@ -4139,22 +4363,23 @@ static drflac_bool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, i case DRFLAC_SUBFRAME_LPC: { + unsigned char lpcPrecision; + unsigned int bitsToSeek = pSubframe->lpcOrder * pSubframe->bitsPerSample; if (!drflac__seek_bits(bs, bitsToSeek)) { return DRFLAC_FALSE; } - unsigned char lpcPrecision; if (!drflac__read_uint8(bs, 4, &lpcPrecision)) { return DRFLAC_FALSE; } if (lpcPrecision == 15) { - return DRFLAC_FALSE; // Invalid. + return DRFLAC_FALSE; /* Invalid. */ } lpcPrecision += 1; - bitsToSeek = (pSubframe->lpcOrder * lpcPrecision) + 5; // +5 for shift. + bitsToSeek = (pSubframe->lpcOrder * lpcPrecision) + 5; /* +5 for shift. */ if (!drflac__seek_bits(bs, bitsToSeek)) { return DRFLAC_FALSE; } @@ -4173,35 +4398,43 @@ static drflac_bool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, i static DRFLAC_INLINE drflac_uint8 drflac__get_channel_count_from_channel_assignment(drflac_int8 channelAssignment) { - drflac_assert(channelAssignment <= 10); - 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) { - // This function should be called while the stream is sitting on the first byte after the frame header. + 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->currentFrame.subframes, sizeof(pFlac->currentFrame.subframes)); - // The frame block size must never be larger than the maximum block size defined by the FLAC stream. + /* The frame block size must never be larger than the maximum block size defined by the FLAC stream. */ if (pFlac->currentFrame.header.blockSize > pFlac->maxBlockSize) { return DRFLAC_ERROR; } - // The number of channels in the frame must match the channel count from the STREAMINFO block. - int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment); + /* 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->currentFrame.header.channelAssignment); if (channelCount != (int)pFlac->channels) { return DRFLAC_ERROR; } - for (int i = 0; i < channelCount; ++i) { + for (i = 0; i < channelCount; ++i) { if (!drflac__decode_subframe(&pFlac->bs, &pFlac->currentFrame, i, pFlac->pDecodedSamples + ((pFlac->currentFrame.header.blockSize+DRFLAC_LEADING_SAMPLES) * i) + DRFLAC_LEADING_SAMPLES)) { return DRFLAC_ERROR; } } - drflac_uint8 paddingSizeInBits = DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7; + paddingSizeInBits = DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7; if (paddingSizeInBits > 0) { drflac_uint8 padding = 0; if (!drflac__read_uint8(&pFlac->bs, paddingSizeInBits, &padding)) { @@ -4210,16 +4443,15 @@ static drflac_result drflac__decode_flac_frame(drflac* pFlac) } #ifndef DR_FLAC_NO_CRC - drflac_uint16 actualCRC16 = drflac__flush_crc16(&pFlac->bs); + actualCRC16 = drflac__flush_crc16(&pFlac->bs); #endif - drflac_uint16 desiredCRC16; if (!drflac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) { return DRFLAC_END_OF_STREAM; } #ifndef DR_FLAC_NO_CRC if (actualCRC16 != desiredCRC16) { - return DRFLAC_CRC_MISMATCH; // CRC mismatch. + return DRFLAC_CRC_MISMATCH; /* CRC mismatch. */ } #endif @@ -4230,30 +4462,36 @@ static drflac_result drflac__decode_flac_frame(drflac* pFlac) static drflac_result drflac__seek_flac_frame(drflac* pFlac) { - int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment); - for (int i = 0; i < channelCount; ++i) { + 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->currentFrame.header.channelAssignment); + for (i = 0; i < channelCount; ++i) { if (!drflac__seek_subframe(&pFlac->bs, &pFlac->currentFrame, i)) { return DRFLAC_ERROR; } } - // Padding. + /* Padding. */ if (!drflac__seek_bits(&pFlac->bs, DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7)) { return DRFLAC_ERROR; } - // CRC. + /* CRC. */ #ifndef DR_FLAC_NO_CRC - drflac_uint16 actualCRC16 = drflac__flush_crc16(&pFlac->bs); + actualCRC16 = drflac__flush_crc16(&pFlac->bs); #endif - drflac_uint16 desiredCRC16; if (!drflac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) { return DRFLAC_END_OF_STREAM; } #ifndef DR_FLAC_NO_CRC if (actualCRC16 != desiredCRC16) { - return DRFLAC_CRC_MISMATCH; // CRC mismatch. + return DRFLAC_CRC_MISMATCH; /* CRC mismatch. */ } #endif @@ -4265,14 +4503,16 @@ 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->currentFrame.header)) { return DRFLAC_FALSE; } - drflac_result result = drflac__decode_flac_frame(pFlac); + result = drflac__decode_flac_frame(pFlac); if (result != DRFLAC_SUCCESS) { if (result == DRFLAC_CRC_MISMATCH) { - continue; // CRC mismatch. Skip to the next frame. + continue; /* CRC mismatch. Skip to the next frame. */ } else { return DRFLAC_FALSE; } @@ -4285,38 +4525,49 @@ static drflac_bool32 drflac__read_and_decode_next_flac_frame(drflac* pFlac) static void drflac__get_current_frame_sample_range(drflac* pFlac, drflac_uint64* pFirstSampleInFrameOut, drflac_uint64* pLastSampleInFrameOut) { + unsigned int channelCount; + drflac_uint64 firstSampleInFrame; + drflac_uint64 lastSampleInFrame; + drflac_assert(pFlac != NULL); - unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment); + channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment); - drflac_uint64 firstSampleInFrame = pFlac->currentFrame.header.sampleNumber*channelCount; + firstSampleInFrame = pFlac->currentFrame.header.sampleNumber*channelCount; if (firstSampleInFrame == 0) { firstSampleInFrame = pFlac->currentFrame.header.frameNumber * pFlac->maxBlockSize*channelCount; } - drflac_uint64 lastSampleInFrame = firstSampleInFrame + (pFlac->currentFrame.header.blockSize*channelCount); + lastSampleInFrame = firstSampleInFrame + (pFlac->currentFrame.header.blockSize*channelCount); if (lastSampleInFrame > 0) { - lastSampleInFrame -= 1; // Needs to be zero based. + lastSampleInFrame -= 1; /* Needs to be zero based. */ } - if (pFirstSampleInFrameOut) *pFirstSampleInFrameOut = firstSampleInFrame; - if (pLastSampleInFrameOut) *pLastSampleInFrameOut = lastSampleInFrame; + if (pFirstSampleInFrameOut) { + *pFirstSampleInFrameOut = firstSampleInFrame; + } + if (pLastSampleInFrameOut) { + *pLastSampleInFrameOut = lastSampleInFrame; + } } /* This function will be replacing drflac__get_current_frame_sample_range(), but it's not currently used so I have commented it out to silence a compiler warning. */ #if 0 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); - drflac_uint64 firstPCMFrame = pFlac->currentFrame.header.sampleNumber; + firstPCMFrame = pFlac->currentFrame.header.sampleNumber; if (firstPCMFrame == 0) { firstPCMFrame = pFlac->currentFrame.header.frameNumber * pFlac->maxBlockSize; } - drflac_uint64 lastPCMFrame = firstPCMFrame + (pFlac->currentFrame.header.blockSize); + lastPCMFrame = firstPCMFrame + (pFlac->currentFrame.header.blockSize); if (lastPCMFrame > 0) { - lastPCMFrame -= 1; // Needs to be zero based. + lastPCMFrame -= 1; /* Needs to be zero based. */ } if (pFirstPCMFrame) { @@ -4330,9 +4581,11 @@ static void drflac__get_pcm_frame_range_of_current_flac_frame(drflac* pFlac, drf static drflac_bool32 drflac__seek_to_first_frame(drflac* pFlac) { + drflac_bool32 result; + drflac_assert(pFlac != NULL); - drflac_bool32 result = drflac__seek_to_byte(&pFlac->bs, pFlac->firstFramePos); + result = drflac__seek_to_byte(&pFlac->bs, pFlac->firstFramePos); drflac_zero_memory(&pFlac->currentFrame, sizeof(pFlac->currentFrame)); pFlac->currentSample = 0; @@ -4342,7 +4595,7 @@ static drflac_bool32 drflac__seek_to_first_frame(drflac* pFlac) 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. + /* 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); } @@ -4353,12 +4606,12 @@ drflac_uint64 drflac__seek_forward_by_samples(drflac* pFlac, drflac_uint64 sampl while (samplesToRead > 0) { if (pFlac->currentFrame.samplesRemaining == 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. + break; /* Couldn't read the next frame, so just break from the loop and return. */ } } else { if (pFlac->currentFrame.samplesRemaining > samplesToRead) { samplesRead += samplesToRead; - pFlac->currentFrame.samplesRemaining -= (drflac_uint32)samplesToRead; // <-- Safe cast. Will always be < currentFrame.samplesRemaining < 65536. + pFlac->currentFrame.samplesRemaining -= (drflac_uint32)samplesToRead; /* <-- Safe cast. Will always be < currentFrame.samplesRemaining < 65536. */ samplesToRead = 0; } else { samplesRead += pFlac->currentFrame.samplesRemaining; @@ -4379,17 +4632,17 @@ drflac_uint64 drflac__seek_forward_by_pcm_frames(drflac* pFlac, drflac_uint64 pc static drflac_bool32 drflac__seek_to_sample__brute_force(drflac* pFlac, drflac_uint64 sampleIndex) { + drflac_bool32 isMidFrame = DRFLAC_FALSE; + drflac_uint64 runningSampleCount; + drflac_assert(pFlac != NULL); - drflac_bool32 isMidFrame = DRFLAC_FALSE; - - // 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. - drflac_uint64 runningSampleCount; + /* 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 (sampleIndex >= pFlac->currentSample) { - // Seeking forward. Need to seek from the current position. + /* Seeking forward. Need to seek from the current position. */ runningSampleCount = pFlac->currentSample; - // The frame header for the first frame may not yet have been read. We need to do that if necessary. + /* The frame header for the first frame may not yet have been read. We need to do that if necessary. */ if (pFlac->currentSample == 0 && pFlac->currentFrame.samplesRemaining == 0) { if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFrame.header)) { return DRFLAC_FALSE; @@ -4398,66 +4651,76 @@ static drflac_bool32 drflac__seek_to_sample__brute_force(drflac* pFlac, drflac_u isMidFrame = DRFLAC_TRUE; } } else { - // Seeking backwards. Need to seek from the start of the file. + /* Seeking backwards. Need to seek from the start of the file. */ runningSampleCount = 0; - // Move back to the start. + /* 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. + /* Decode the first frame in preparation for sample-exact seeking below. */ if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFrame.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. + /* + 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 sampleCountInThisFrame; drflac_uint64 firstSampleInFrame = 0; drflac_uint64 lastSampleInFrame = 0; + drflac__get_current_frame_sample_range(pFlac, &firstSampleInFrame, &lastSampleInFrame); - drflac_uint64 sampleCountInThisFrame = (lastSampleInFrame - firstSampleInFrame) + 1; + sampleCountInThisFrame = (lastSampleInFrame - firstSampleInFrame) + 1; if (sampleIndex < (runningSampleCount + sampleCountInThisFrame)) { - // 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. + /* + 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 samplesToDecode = sampleIndex - runningSampleCount; 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_samples(pFlac, samplesToDecode) == samplesToDecode; // <-- If this fails, something bad has happened (it should never fail). + /* The frame is valid. We just need to skip over some samples to ensure it's sample-exact. */ + return drflac__seek_forward_by_samples(pFlac, samplesToDecode) == samplesToDecode; /* <-- 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. + 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. + /* We started seeking mid-frame which means we need to skip the frame decoding part. */ return drflac__seek_forward_by_samples(pFlac, samplesToDecode) == samplesToDecode; } } 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. + /* + 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) { runningSampleCount += sampleCountInThisFrame; } else { if (result == DRFLAC_CRC_MISMATCH) { - goto next_iteration; // CRC mismatch. Pretend this frame never existed. + 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. + /* + 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. + */ runningSampleCount += pFlac->currentFrame.samplesRemaining; pFlac->currentFrame.samplesRemaining = 0; isMidFrame = DRFLAC_FALSE; @@ -4465,7 +4728,7 @@ static drflac_bool32 drflac__seek_to_sample__brute_force(drflac* pFlac, drflac_u } next_iteration: - // Grab the next frame in preparation for the next iteration. + /* Grab the next frame in preparation for the next iteration. */ if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFrame.header)) { return DRFLAC_FALSE; } @@ -4475,15 +4738,18 @@ static drflac_bool32 drflac__seek_to_sample__brute_force(drflac* pFlac, drflac_u static drflac_bool32 drflac__seek_to_sample__seek_table(drflac* pFlac, drflac_uint64 sampleIndex) { + drflac_uint32 iClosestSeekpoint = 0; + drflac_bool32 isMidFrame = DRFLAC_FALSE; + drflac_uint64 runningSampleCount; + drflac_uint32 iSeekpoint; + drflac_assert(pFlac != NULL); if (pFlac->pSeekpoints == NULL || pFlac->seekpointCount == 0) { return DRFLAC_FALSE; } - - drflac_uint32 iClosestSeekpoint = 0; - for (drflac_uint32 iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) { + for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) { if (pFlac->pSeekpoints[iSeekpoint].firstSample*pFlac->channels >= sampleIndex) { break; } @@ -4491,17 +4757,15 @@ static drflac_bool32 drflac__seek_to_sample__seek_table(drflac* pFlac, drflac_ui iClosestSeekpoint = iSeekpoint; } - - drflac_bool32 isMidFrame = DRFLAC_FALSE; - - // At this point we should have found the seekpoint closest to our sample. 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. - drflac_uint64 runningSampleCount; + /* + At this point we should have found the seekpoint closest to our sample. 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 ((sampleIndex >= pFlac->currentSample) && (pFlac->pSeekpoints[iClosestSeekpoint].firstSample*pFlac->channels <= pFlac->currentSample)) { - // Optimized case. Just seek forward from where we are. + /* Optimized case. Just seek forward from where we are. */ runningSampleCount = pFlac->currentSample; - // The frame header for the first frame may not yet have been read. We need to do that if necessary. + /* The frame header for the first frame may not yet have been read. We need to do that if necessary. */ if (pFlac->currentSample == 0 && pFlac->currentFrame.samplesRemaining == 0) { if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFrame.header)) { return DRFLAC_FALSE; @@ -4510,63 +4774,70 @@ static drflac_bool32 drflac__seek_to_sample__seek_table(drflac* pFlac, drflac_ui isMidFrame = DRFLAC_TRUE; } } else { - // Slower case. Seek to the start of the seekpoint and then seek forward from there. + /* Slower case. Seek to the start of the seekpoint and then seek forward from there. */ runningSampleCount = pFlac->pSeekpoints[iClosestSeekpoint].firstSample*pFlac->channels; if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFramePos + pFlac->pSeekpoints[iClosestSeekpoint].frameOffset)) { return DRFLAC_FALSE; } - // Grab the frame the seekpoint is sitting on in preparation for the sample-exact seeking below. + /* 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->currentFrame.header)) { return DRFLAC_FALSE; } } for (;;) { + drflac_uint64 sampleCountInThisFrame; drflac_uint64 firstSampleInFrame = 0; drflac_uint64 lastSampleInFrame = 0; drflac__get_current_frame_sample_range(pFlac, &firstSampleInFrame, &lastSampleInFrame); - drflac_uint64 sampleCountInThisFrame = (lastSampleInFrame - firstSampleInFrame) + 1; + sampleCountInThisFrame = (lastSampleInFrame - firstSampleInFrame) + 1; if (sampleIndex < (runningSampleCount + sampleCountInThisFrame)) { - // 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. + /* + 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 samplesToDecode = sampleIndex - runningSampleCount; 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_samples(pFlac, samplesToDecode) == samplesToDecode; // <-- If this fails, something bad has happened (it should never fail). + /* The frame is valid. We just need to skip over some samples to ensure it's sample-exact. */ + return drflac__seek_forward_by_samples(pFlac, samplesToDecode) == samplesToDecode; /* <-- 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. + 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. + /* We started seeking mid-frame which means we need to skip the frame decoding part. */ return drflac__seek_forward_by_samples(pFlac, samplesToDecode) == samplesToDecode; } } 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. + /* + 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) { runningSampleCount += sampleCountInThisFrame; } else { if (result == DRFLAC_CRC_MISMATCH) { - goto next_iteration; // CRC mismatch. Pretend this frame never existed. + 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. + /* + 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. + */ runningSampleCount += pFlac->currentFrame.samplesRemaining; pFlac->currentFrame.samplesRemaining = 0; isMidFrame = DRFLAC_FALSE; @@ -4574,7 +4845,7 @@ static drflac_bool32 drflac__seek_to_sample__seek_table(drflac* pFlac, drflac_ui } next_iteration: - // Grab the next frame in preparation for the next iteration. + /* Grab the next frame in preparation for the next iteration. */ if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFrame.header)) { return DRFLAC_FALSE; } @@ -4585,8 +4856,8 @@ static drflac_bool32 drflac__seek_to_sample__seek_table(drflac* pFlac, drflac_ui #ifndef DR_FLAC_NO_OGG typedef struct { - drflac_uint8 capturePattern[4]; // Should be "OggS" - drflac_uint8 structureVersion; // Always 0. + drflac_uint8 capturePattern[4]; /* Should be "OggS" */ + drflac_uint8 structureVersion; /* Always 0. */ drflac_uint8 headerType; drflac_uint64 granulePosition; drflac_uint32 serialNumber; @@ -4613,8 +4884,8 @@ typedef struct 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. + 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; @@ -4644,26 +4915,27 @@ static DRFLAC_INLINE drflac_bool32 drflac__read_and_decode_block_header(drflac_r drflac_bool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, drflac_streaminfo* pStreamInfo) { - // min/max block size. 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. - drflac_uint64 frameSizes = 0; + /* min/max frame size. */ if (onRead(pUserData, &frameSizes, 6) != 6) { return DRFLAC_FALSE; } - // Sample rate, channels, bits per sample and total sample count. - drflac_uint64 importantProps; + /* Sample rate, channels, bits per sample and total sample count. */ if (onRead(pUserData, &importantProps, 8) != 8) { return DRFLAC_FALSE; } - // MD5 - drflac_uint8 md5[16]; + /* MD5 */ if (onRead(pUserData, md5, sizeof(md5)) != sizeof(md5)) { return DRFLAC_FALSE; } @@ -4673,13 +4945,13 @@ drflac_bool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, importantProps = drflac__be2host_64(importantProps); pStreamInfo->minBlockSize = (blockSizes & 0xFFFF0000) >> 16; - pStreamInfo->maxBlockSize = blockSizes & 0x0000FFFF; - pStreamInfo->minFrameSize = (drflac_uint32)((frameSizes & (drflac_uint64)0xFFFFFF0000000000) >> 40); - pStreamInfo->maxFrameSize = (drflac_uint32)((frameSizes & (drflac_uint64)0x000000FFFFFF0000) >> 16); - pStreamInfo->sampleRate = (drflac_uint32)((importantProps & (drflac_uint64)0xFFFFF00000000000) >> 44); - pStreamInfo->channels = (drflac_uint8 )((importantProps & (drflac_uint64)0x00000E0000000000) >> 41) + 1; - pStreamInfo->bitsPerSample = (drflac_uint8 )((importantProps & (drflac_uint64)0x000001F000000000) >> 36) + 1; - pStreamInfo->totalSampleCount = (importantProps & (drflac_uint64)0x0000000FFFFFFFFF) * pStreamInfo->channels; + pStreamInfo->maxBlockSize = (blockSizes & 0x0000FFFF); + pStreamInfo->minFrameSize = (drflac_uint32)((frameSizes & (((drflac_uint64)0x00FFFFFF << 16) << 24)) >> 40); + pStreamInfo->maxFrameSize = (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->totalSampleCount = ((importantProps & ((((drflac_uint64)0x0000000F << 16) << 16) | 0xFFFFFFFF))) * pStreamInfo->channels; drflac_copy_memory(pStreamInfo->md5, md5, sizeof(md5)); return DRFLAC_TRUE; @@ -4687,13 +4959,16 @@ drflac_bool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_uint64* pFirstFramePos, drflac_uint64* pSeektablePos, drflac_uint32* pSeektableSize) { - // We want to keep track of the byte position in the stream of the seektable. At the time of calling this function we know that - // we'll be sitting on byte 42. + /* + We want to keep track of the byte position in the stream of the seektable. At the time of calling this function we know that + we'll be sitting on byte 42. + */ drflac_uint64 runningFilePos = 42; drflac_uint64 seektablePos = 0; drflac_uint32 seektableSize = 0; for (;;) { + drflac_metadata metadata; drflac_uint8 isLastBlock = 0; drflac_uint8 blockType; drflac_uint32 blockSize; @@ -4702,8 +4977,6 @@ drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_s } runningFilePos += 4; - - drflac_metadata metadata; metadata.type = blockType; metadata.pRawData = NULL; metadata.rawDataSize = 0; @@ -4744,7 +5017,10 @@ drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_s seektableSize = blockSize; if (onMeta) { - void* pRawData = DRFLAC_MALLOC(blockSize); + drflac_uint32 iSeekpoint; + void* pRawData; + + pRawData = DRFLAC_MALLOC(blockSize); if (pRawData == NULL) { return DRFLAC_FALSE; } @@ -4759,8 +5035,8 @@ drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_s metadata.data.seektable.seekpointCount = blockSize/sizeof(drflac_seekpoint); metadata.data.seektable.pSeekpoints = (const drflac_seekpoint*)pRawData; - // Endian swap. - for (drflac_uint32 iSeekpoint = 0; iSeekpoint < metadata.data.seektable.seekpointCount; ++iSeekpoint) { + /* Endian swap. */ + for (iSeekpoint = 0; iSeekpoint < metadata.data.seektable.seekpointCount; ++iSeekpoint) { drflac_seekpoint* pSeekpoint = (drflac_seekpoint*)pRawData + iSeekpoint; pSeekpoint->firstSample = drflac__be2host_64(pSeekpoint->firstSample); pSeekpoint->frameOffset = drflac__be2host_64(pSeekpoint->frameOffset); @@ -4780,7 +5056,12 @@ drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_s } if (onMeta) { - void* pRawData = DRFLAC_MALLOC(blockSize); + void* pRawData; + const char* pRunningData; + const char* pRunningDataEnd; + drflac_uint32 i; + + pRawData = DRFLAC_MALLOC(blockSize); if (pRawData == NULL) { return DRFLAC_FALSE; } @@ -4793,34 +5074,37 @@ drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_s metadata.pRawData = pRawData; metadata.rawDataSize = blockSize; - const char* pRunningData = (const char*)pRawData; - const char* const pRunningDataEnd = (const char*)pRawData + blockSize; + pRunningData = (const char*)pRawData; + pRunningDataEnd = (const char*)pRawData + blockSize; metadata.data.vorbis_comment.vendorLength = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; - // Need space for the rest of the block - if ((pRunningDataEnd - pRunningData) - 4 < (drflac_int64)metadata.data.vorbis_comment.vendorLength) { // <-- Note the order of operations to avoid overflow to a valid value + /* Need space for the rest of the block */ + if ((pRunningDataEnd - pRunningData) - 4 < (drflac_int64)metadata.data.vorbis_comment.vendorLength) { /* <-- Note the order of operations to avoid overflow to a valid value */ DRFLAC_FREE(pRawData); return DRFLAC_FALSE; } metadata.data.vorbis_comment.vendor = pRunningData; pRunningData += metadata.data.vorbis_comment.vendorLength; metadata.data.vorbis_comment.commentCount = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; - // Need space for 'commentCount' comments after the block, which at minimum is a drflac_uint32 per comment - if ((pRunningDataEnd - pRunningData) / sizeof(drflac_uint32) < metadata.data.vorbis_comment.commentCount) { // <-- Note the order of operations to avoid overflow to a valid value + /* Need space for 'commentCount' comments after the block, which at minimum is a drflac_uint32 per comment */ + if ((pRunningDataEnd - pRunningData) / sizeof(drflac_uint32) < metadata.data.vorbis_comment.commentCount) { /* <-- Note the order of operations to avoid overflow to a valid value */ DRFLAC_FREE(pRawData); return DRFLAC_FALSE; } metadata.data.vorbis_comment.pComments = pRunningData; - // Check that the comments section is valid before passing it to the callback - for (drflac_uint32 i = 0; i < metadata.data.vorbis_comment.commentCount; ++i) { + /* Check that the comments section is valid before passing it to the callback */ + for (i = 0; i < metadata.data.vorbis_comment.commentCount; ++i) { + drflac_uint32 commentLength; + if (pRunningDataEnd - pRunningData < 4) { DRFLAC_FREE(pRawData); return DRFLAC_FALSE; } - const drflac_uint32 commentLength = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; - if (pRunningDataEnd - pRunningData < (drflac_int64)commentLength) { // <-- Note the order of operations to avoid overflow to a valid value + + commentLength = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + if (pRunningDataEnd - pRunningData < (drflac_int64)commentLength) { /* <-- Note the order of operations to avoid overflow to a valid value */ DRFLAC_FREE(pRawData); return DRFLAC_FALSE; } @@ -4840,7 +5124,13 @@ drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_s } if (onMeta) { - void* pRawData = DRFLAC_MALLOC(blockSize); + void* pRawData; + const char* pRunningData; + const char* pRunningDataEnd; + drflac_uint8 iTrack; + drflac_uint8 iIndex; + + pRawData = DRFLAC_MALLOC(blockSize); if (pRawData == NULL) { return DRFLAC_FALSE; } @@ -4853,8 +5143,8 @@ drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_s metadata.pRawData = pRawData; metadata.rawDataSize = blockSize; - char* pRunningData = (char*)pRawData; - const char* const pRunningDataEnd = (const char*)pRawData + blockSize; + pRunningData = (const char*)pRawData; + pRunningDataEnd = (const char*)pRawData + blockSize; drflac_copy_memory(metadata.data.cuesheet.catalog, pRunningData, 128); pRunningData += 128; metadata.data.cuesheet.leadInSampleCount = drflac__be2host_64(*(const drflac_uint64*)pRunningData); pRunningData += 8; @@ -4862,24 +5152,27 @@ drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_s metadata.data.cuesheet.trackCount = pRunningData[0]; pRunningData += 1; metadata.data.cuesheet.pTrackData = pRunningData; - // Check that the cuesheet tracks are valid before passing it to the callback - for (drflac_uint8 i = 0; i < metadata.data.cuesheet.trackCount; ++i) { + /* Check that the cuesheet tracks are valid before passing it to the callback */ + for (iTrack = 0; iTrack < metadata.data.cuesheet.trackCount; ++iTrack) { + drflac_uint8 indexCount; + drflac_uint32 indexPointSize; + if (pRunningDataEnd - pRunningData < 36) { DRFLAC_FREE(pRawData); return DRFLAC_FALSE; } - // Skip to the index point count + /* Skip to the index point count */ pRunningData += 35; - const drflac_uint8 indexCount = pRunningData[0]; pRunningData += 1; - const drflac_uint32 indexPointSize = indexCount * sizeof(drflac_cuesheet_track_index); + indexCount = pRunningData[0]; pRunningData += 1; + indexPointSize = indexCount * sizeof(drflac_cuesheet_track_index); if (pRunningDataEnd - pRunningData < (drflac_int64)indexPointSize) { DRFLAC_FREE(pRawData); return DRFLAC_FALSE; } - // Endian swap. - for (drflac_uint8 index = 0; index < indexCount; ++index) { + /* Endian swap. */ + for (iIndex = 0; iIndex < indexCount; ++iIndex) { drflac_cuesheet_track_index* pTrack = (drflac_cuesheet_track_index*)pRunningData; pRunningData += sizeof(drflac_cuesheet_track_index); pTrack->offset = drflac__be2host_64(pTrack->offset); @@ -4899,7 +5192,11 @@ drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_s } if (onMeta) { - void* pRawData = DRFLAC_MALLOC(blockSize); + void* pRawData; + const char* pRunningData; + const char* pRunningDataEnd; + + pRawData = DRFLAC_MALLOC(blockSize); if (pRawData == NULL) { return DRFLAC_FALSE; } @@ -4912,35 +5209,35 @@ drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_s metadata.pRawData = pRawData; metadata.rawDataSize = blockSize; - const char* pRunningData = (const char*)pRawData; - const char* const pRunningDataEnd = (const char*)pRawData + blockSize; + pRunningData = (const char*)pRawData; + pRunningDataEnd = (const char*)pRawData + blockSize; - metadata.data.picture.type = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.mimeLength = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.type = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.mimeLength = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; - // Need space for the rest of the block - if ((pRunningDataEnd - pRunningData) - 24 < (drflac_int64)metadata.data.picture.mimeLength) { // <-- Note the order of operations to avoid overflow to a valid value + /* Need space for the rest of the block */ + if ((pRunningDataEnd - pRunningData) - 24 < (drflac_int64)metadata.data.picture.mimeLength) { /* <-- Note the order of operations to avoid overflow to a valid value */ DRFLAC_FREE(pRawData); return DRFLAC_FALSE; } metadata.data.picture.mime = pRunningData; pRunningData += metadata.data.picture.mimeLength; metadata.data.picture.descriptionLength = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; - // Need space for the rest of the block - if ((pRunningDataEnd - pRunningData) - 20 < (drflac_int64)metadata.data.picture.descriptionLength) { // <-- Note the order of operations to avoid overflow to a valid value + /* Need space for the rest of the block */ + if ((pRunningDataEnd - pRunningData) - 20 < (drflac_int64)metadata.data.picture.descriptionLength) { /* <-- Note the order of operations to avoid overflow to a valid value */ DRFLAC_FREE(pRawData); return DRFLAC_FALSE; } - metadata.data.picture.description = pRunningData; pRunningData += metadata.data.picture.descriptionLength; - metadata.data.picture.width = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.height = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.colorDepth = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.indexColorCount = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.pictureDataSize = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; - metadata.data.picture.pPictureData = (const drflac_uint8*)pRunningData; + metadata.data.picture.description = pRunningData; pRunningData += metadata.data.picture.descriptionLength; + metadata.data.picture.width = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.height = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.colorDepth = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.indexColorCount = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.pictureDataSize = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + metadata.data.picture.pPictureData = (const drflac_uint8*)pRunningData; - // Need space for the picture after the block - if (pRunningDataEnd - pRunningData < (drflac_int64)metadata.data.picture.pictureDataSize) { // <-- Note the order of operations to avoid overflow to a valid value + /* Need space for the picture after the block */ + if (pRunningDataEnd - pRunningData < (drflac_int64)metadata.data.picture.pictureDataSize) { /* <-- Note the order of operations to avoid overflow to a valid value */ DRFLAC_FREE(pRawData); return DRFLAC_FALSE; } @@ -4956,9 +5253,9 @@ drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_s if (onMeta) { metadata.data.padding.unused = 0; - // Padding doesn't have anything meaningful in it, so just skip over it, but make sure the caller is aware of it by firing the callback. + /* Padding doesn't have anything meaningful in it, so just skip over it, but make sure the caller is aware of it by firing the callback. */ if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) { - isLastBlock = DRFLAC_TRUE; // An error occurred while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. + isLastBlock = DRFLAC_TRUE; /* An error occurred while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. */ } else { onMeta(pUserDataMD, &metadata); } @@ -4967,18 +5264,20 @@ drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_s case DRFLAC_METADATA_BLOCK_TYPE_INVALID: { - // Invalid chunk. Just skip over this one. + /* Invalid chunk. Just skip over this one. */ if (onMeta) { if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) { - isLastBlock = DRFLAC_TRUE; // An error occurred while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. + isLastBlock = DRFLAC_TRUE; /* An error occurred while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. */ } } } break; default: { - // It's an unknown chunk, but not necessarily invalid. There's a chance more metadata blocks might be defined later on, so we - // can at the very least report the chunk to the application and let it look at the raw data. + /* + It's an unknown chunk, but not necessarily invalid. There's a chance more metadata blocks might be defined later on, so we + can at the very least report the chunk to the application and let it look at the raw data. + */ if (onMeta) { void* pRawData = DRFLAC_MALLOC(blockSize); if (pRawData == NULL) { @@ -4999,7 +5298,7 @@ drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_s } 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 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; @@ -5021,42 +5320,45 @@ drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_s 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) { - (void)onSeek; + /* Pre Condition: The bit stream should be sitting just past the 4-byte id header. */ - // Pre: The bit stream should be sitting just past the 4-byte id header. - - pInit->container = drflac_container_native; - - // The first metadata block should be the STREAMINFO block. 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. + /* 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. + /* + 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. + 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. + 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->maxBlockSize = 65535; // <-- See notes here: https://xiph.org/flac/format.html#metadata_block_streaminfo + pInit->maxBlockSize = 65535; /* <-- See notes here: https://xiph.org/flac/format.html#metadata_block_streaminfo */ return DRFLAC_TRUE; } } else { @@ -5070,7 +5372,7 @@ drflac_bool32 drflac__init_private__native(drflac_init_info* pInit, drflac_read_ pInit->channels = streaminfo.channels; pInit->bitsPerSample = streaminfo.bitsPerSample; pInit->totalSampleCount = streaminfo.totalSampleCount; - pInit->maxBlockSize = streaminfo.maxBlockSize; // Don't care about the min block size - only the max (used for determining the size of the memory allocation). + pInit->maxBlockSize = streaminfo.maxBlockSize; /* 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) { @@ -5088,7 +5390,7 @@ drflac_bool32 drflac__init_private__native(drflac_init_info* pInit, drflac_read_ #ifndef DR_FLAC_NO_OGG #define DRFLAC_OGG_MAX_PAGE_SIZE 65307 -#define DRFLAC_OGG_CAPTURE_PATTERN_CRC32 1605413199 // CRC-32 of "OggS". +#define DRFLAC_OGG_CAPTURE_PATTERN_CRC32 1605413199 /* CRC-32 of "OggS". */ typedef enum { @@ -5096,7 +5398,7 @@ typedef enum 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, @@ -5163,6 +5465,7 @@ static drflac_uint32 drflac__crc32_table[] = { 0xAFB010B1L, 0xAB710D06L, 0xA6322BDFL, 0xA2F33668L, 0xBCB4666DL, 0xB8757BDAL, 0xB5365D03L, 0xB1F740B4L }; +#endif static DRFLAC_INLINE drflac_uint32 drflac_crc32_byte(drflac_uint32 crc32, drflac_uint8 data) { @@ -5194,8 +5497,9 @@ static DRFLAC_INLINE drflac_uint32 drflac_crc32_uint64(drflac_uint32 crc32, drfl static DRFLAC_INLINE drflac_uint32 drflac_crc32_buffer(drflac_uint32 crc32, drflac_uint8* pData, drflac_uint32 dataSize) { - // This can be optimized. - for (drflac_uint32 i = 0; i < dataSize; ++i) { + /* This can be optimized. */ + drflac_uint32 i; + for (i = 0; i < dataSize; ++i) { crc32 = drflac_crc32_byte(crc32, pData[i]); } return crc32; @@ -5215,7 +5519,9 @@ static DRFLAC_INLINE drflac_uint32 drflac_ogg__get_page_header_size(drflac_ogg_p static DRFLAC_INLINE drflac_uint32 drflac_ogg__get_page_body_size(drflac_ogg_page_header* pHeader) { drflac_uint32 pageBodySize = 0; - for (int i = 0; i < pHeader->segmentCount; ++i) { + int i; + + for (i = 0; i < pHeader->segmentCount; ++i) { pageBodySize += pHeader->segmentTable[i]; } @@ -5224,9 +5530,11 @@ static DRFLAC_INLINE drflac_uint32 drflac_ogg__get_page_body_size(drflac_ogg_pag drflac_result drflac_ogg__read_page_header_after_capture_pattern(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, drflac_uint32* pBytesRead, drflac_uint32* pCRC32) { + drflac_uint8 data[23]; + drflac_uint32 i; + drflac_assert(*pCRC32 == DRFLAC_OGG_CAPTURE_PATTERN_CRC32); - drflac_uint8 data[23]; if (onRead(pUserData, data, 23) != 23) { return DRFLAC_END_OF_STREAM; } @@ -5240,13 +5548,12 @@ drflac_result drflac_ogg__read_page_header_after_capture_pattern(drflac_read_pro drflac_copy_memory(&pHeader->checksum, &data[18], 4); pHeader->segmentCount = data[22]; - // Calculate the CRC. Note that for the calculation the checksum part of the page needs to be set to 0. + /* Calculate the CRC. Note that for the calculation the checksum part of the page needs to be set to 0. */ data[18] = 0; data[19] = 0; data[20] = 0; data[21] = 0; - drflac_uint32 i; for (i = 0; i < 23; ++i) { *pCRC32 = drflac_crc32_byte(*pCRC32, data[i]); } @@ -5266,20 +5573,23 @@ drflac_result drflac_ogg__read_page_header_after_capture_pattern(drflac_read_pro drflac_result drflac_ogg__read_page_header(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, drflac_uint32* pBytesRead, drflac_uint32* pCRC32) { + drflac_uint8 id[4]; + *pBytesRead = 0; - drflac_uint8 id[4]; if (onRead(pUserData, id, 4) != 4) { return DRFLAC_END_OF_STREAM; } *pBytesRead += 4; - // We need to read byte-by-byte until we find the OggS capture pattern. + /* We need to read byte-by-byte until we find the OggS capture pattern. */ for (;;) { if (drflac_ogg__is_capture_pattern(id)) { + drflac_result result; + *pCRC32 = DRFLAC_OGG_CAPTURE_PATTERN_CRC32; - drflac_result result = drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, pHeader, pBytesRead, pCRC32); + result = drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, pHeader, pBytesRead, pCRC32); if (result == DRFLAC_SUCCESS) { return DRFLAC_SUCCESS; } else { @@ -5290,7 +5600,7 @@ drflac_result drflac_ogg__read_page_header(drflac_read_proc onRead, void* pUserD } } } else { - // The first 4 bytes did not equal the capture pattern. Read the next byte and try again. + /* The first 4 bytes did not equal the capture pattern. Read the next byte and try again. */ id[0] = id[1]; id[1] = id[2]; id[2] = id[3]; @@ -5303,25 +5613,27 @@ drflac_result drflac_ogg__read_page_header(drflac_read_proc onRead, void* pUserD } -// The main part of the Ogg encapsulation is the conversion from the physical Ogg bitstream to the native FLAC bitstream. It works -// in three general stages: Ogg Physical Bitstream -> Ogg/FLAC Logical Bitstream -> FLAC Native Bitstream. dr_flac is designed -// in such a way that the core sections assume everything is delivered in native format. Therefore, for each encapsulation type -// dr_flac is supporting there needs to be a layer sitting on top of the onRead and onSeek callbacks that ensures the bits read from -// the physical Ogg bitstream are converted and delivered in native FLAC format. +/* +The main part of the Ogg encapsulation is the conversion from the physical Ogg bitstream to the native FLAC bitstream. It works +in three general stages: Ogg Physical Bitstream -> Ogg/FLAC Logical Bitstream -> FLAC Native Bitstream. dr_flac is designed +in such a way that the core sections assume everything is delivered in native format. Therefore, for each encapsulation type +dr_flac is supporting there needs to be a layer sitting on top of the onRead and onSeek callbacks that ensures the bits read from +the physical Ogg bitstream are converted and delivered in native FLAC format. +*/ typedef struct { - drflac_read_proc onRead; // The original onRead callback from drflac_open() and family. - drflac_seek_proc onSeek; // The original onSeek callback from drflac_open() and family. - void* pUserData; // The user data passed on onRead and onSeek. This is the user data that was passed on drflac_open() and family. - drflac_uint64 currentBytePos; // The position of the byte we are sitting on in the physical byte stream. Used for efficient seeking. - drflac_uint64 firstBytePos; // The position of the first byte in the physical bitstream. Points to the start of the "OggS" identifier of the FLAC bos page. - drflac_uint32 serialNumber; // The serial number of the FLAC audio pages. This is determined by the initial header page that was read during initialization. - drflac_ogg_page_header bosPageHeader; // Used for seeking. + drflac_read_proc onRead; /* The original onRead callback from drflac_open() and family. */ + drflac_seek_proc onSeek; /* The original onSeek callback from drflac_open() and family. */ + void* pUserData; /* The user data passed on onRead and onSeek. This is the user data that was passed on drflac_open() and family. */ + drflac_uint64 currentBytePos; /* The position of the byte we are sitting on in the physical byte stream. Used for efficient seeking. */ + drflac_uint64 firstBytePos; /* The position of the first byte in the physical bitstream. Points to the start of the "OggS" identifier of the FLAC bos page. */ + drflac_uint32 serialNumber; /* The serial number of the FLAC audio pages. This is determined by the initial header page that was read during initialization. */ + drflac_ogg_page_header bosPageHeader; /* Used for seeking. */ drflac_ogg_page_header currentPageHeader; drflac_uint32 bytesRemainingInPage; drflac_uint32 pageDataSize; drflac_uint8 pageData[DRFLAC_OGG_MAX_PAGE_SIZE]; -} drflac_oggbs; // oggbs = Ogg Bitstream +} drflac_oggbs; /* oggbs = Ogg Bitstream */ static size_t drflac_oggbs__read_physical(drflac_oggbs* oggbs, void* bufferOut, size_t bytesToRead) { @@ -5358,7 +5670,7 @@ static drflac_bool32 drflac_oggbs__seek_physical(drflac_oggbs* oggbs, drflac_uin offset -= 0x7FFFFFFF; } - if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_current)) { // <-- Safe cast thanks to the loop above. + if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_current)) { /* <-- Safe cast thanks to the loop above. */ return DRFLAC_FALSE; } oggbs->currentBytePos += offset; @@ -5373,18 +5685,23 @@ static drflac_bool32 drflac_oggbs__goto_next_page(drflac_oggbs* oggbs, drflac_og for (;;) { drflac_uint32 crc32 = 0; drflac_uint32 bytesRead; + drflac_uint32 pageBodySize; +#ifndef DR_FLAC_NO_CRC + drflac_uint32 actualCRC32; +#endif + if (drflac_ogg__read_page_header(oggbs->onRead, oggbs->pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) { return DRFLAC_FALSE; } oggbs->currentBytePos += bytesRead; - drflac_uint32 pageBodySize = drflac_ogg__get_page_body_size(&header); + pageBodySize = drflac_ogg__get_page_body_size(&header); if (pageBodySize > DRFLAC_OGG_MAX_PAGE_SIZE) { - continue; // Invalid page size. Assume it's corrupted and just move to the next page. + continue; /* Invalid page size. Assume it's corrupted and just move to the next page. */ } if (header.serialNumber != oggbs->serialNumber) { - // It's not a FLAC page. Skip it. + /* It's not a FLAC page. Skip it. */ if (pageBodySize > 0 && !drflac_oggbs__seek_physical(oggbs, pageBodySize, drflac_seek_origin_current)) { return DRFLAC_FALSE; } @@ -5392,27 +5709,29 @@ static drflac_bool32 drflac_oggbs__goto_next_page(drflac_oggbs* oggbs, drflac_og } - // We need to read the entire page and then do a CRC check on it. If there's a CRC mismatch we need to skip this page. + /* We need to read the entire page and then do a CRC check on it. If there's a CRC mismatch we need to skip this page. */ if (drflac_oggbs__read_physical(oggbs, oggbs->pageData, pageBodySize) != pageBodySize) { return DRFLAC_FALSE; } oggbs->pageDataSize = pageBodySize; #ifndef DR_FLAC_NO_CRC - drflac_uint32 actualCRC32 = drflac_crc32_buffer(crc32, oggbs->pageData, oggbs->pageDataSize); + actualCRC32 = drflac_crc32_buffer(crc32, oggbs->pageData, oggbs->pageDataSize); if (actualCRC32 != header.checksum) { if (recoveryMethod == drflac_ogg_recover_on_crc_mismatch) { - continue; // CRC mismatch. Skip this page. + continue; /* CRC mismatch. Skip this page. */ } else { - // Even though we are failing on a CRC mismatch, we still want our stream to be in a good state. Therefore we - // go to the next valid page to ensure we're in a good state, but return false to let the caller know that the - // seek did not fully complete. + /* + Even though we are failing on a CRC mismatch, we still want our stream to be in a good state. Therefore we + go to the next valid page to ensure we're in a good state, but return false to let the caller know that the + seek did not fully complete. + */ drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch); return DRFLAC_FALSE; } } #else - (void)recoveryMethod; // <-- Silence a warning. + (void)recoveryMethod; /* <-- Silence a warning. */ #endif oggbs->currentPageHeader = header; @@ -5421,7 +5740,7 @@ static drflac_bool32 drflac_oggbs__goto_next_page(drflac_oggbs* oggbs, drflac_og } } -// Function below is unused at the moment, but I might be re-adding it later. +/* Function below is unused at the moment, but I might be re-adding it later. */ #if 0 static drflac_uint8 drflac_oggbs__get_current_segment_index(drflac_oggbs* oggbs, drflac_uint8* pBytesRemainingInSeg) { @@ -5444,7 +5763,7 @@ static drflac_uint8 drflac_oggbs__get_current_segment_index(drflac_oggbs* oggbs, 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. + /* 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; @@ -5465,24 +5784,28 @@ static drflac_bool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs) 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. + /* + 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. + /* + 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 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. + /* We're at the next packet. */ return DRFLAC_TRUE; } } @@ -5490,9 +5813,9 @@ static drflac_bool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs) 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. + /* 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. + /* What we're actually doing here is seeking to the start of the next packet. */ return drflac_oggbs__seek_to_next_packet(oggbs); } #endif @@ -5500,12 +5823,13 @@ static drflac_bool32 drflac_oggbs__seek_to_next_frame(drflac_oggbs* oggbs) static size_t drflac__on_read_ogg(void* pUserData, void* bufferOut, size_t bytesToRead) { drflac_oggbs* oggbs = (drflac_oggbs*)pUserData; - drflac_assert(oggbs != NULL); - drflac_uint8* pRunningBufferOut = (drflac_uint8*)bufferOut; - - // Reading is done page-by-page. If we've run out of bytes in the page we need to move to the next one. 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; @@ -5516,7 +5840,7 @@ static size_t drflac__on_read_ogg(void* pUserData, void* bufferOut, size_t bytes break; } - // If we get here it means some of the requested data is contained in the next pages. + /* 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; @@ -5526,7 +5850,7 @@ static size_t drflac__on_read_ogg(void* pUserData, void* bufferOut, size_t bytes 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. + break; /* Failed to go to the next page. Might have simply hit the end of the stream. */ } } @@ -5536,10 +5860,12 @@ static size_t drflac__on_read_ogg(void* pUserData, void* bufferOut, size_t bytes static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_seek_origin origin) { drflac_oggbs* oggbs = (drflac_oggbs*)pUserData; - drflac_assert(oggbs != NULL); - drflac_assert(offset >= 0); // <-- Never seek backwards. + int bytesSeeked = 0; - // Seeking is always forward which makes things a lot simpler. + 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; @@ -5552,10 +5878,8 @@ static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_see return drflac__on_seek_ogg(pUserData, offset, drflac_seek_origin_current); } - drflac_assert(origin == drflac_seek_origin_current); - int bytesSeeked = 0; while (bytesSeeked < offset) { int bytesRemainingToSeek = offset - bytesSeeked; drflac_assert(bytesRemainingToSeek >= 0); @@ -5566,7 +5890,7 @@ static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_see break; } - // If we get here it means some of the requested data is contained in the next pages. + /* 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; @@ -5574,7 +5898,7 @@ static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_see 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. + /* Failed to go to the next page. We either hit the end of the stream or had a CRC mismatch. */ return DRFLAC_FALSE; } } @@ -5585,38 +5909,45 @@ static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_see drflac_bool32 drflac_ogg__seek_to_sample(drflac* pFlac, drflac_uint64 sampleIndex) { drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs; + drflac_uint64 originalBytePos; + drflac_uint64 runningGranulePosition; + drflac_uint64 runningFrameBytePos; + drflac_uint64 runningSampleCount; - drflac_uint64 originalBytePos = oggbs->currentBytePos; // For recovery. + drflac_assert(oggbs != NULL); - // First seek to the first frame. + originalBytePos = oggbs->currentBytePos; /* For recovery. */ + + /* First seek to the first frame. */ if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFramePos)) { return DRFLAC_FALSE; } oggbs->bytesRemainingInPage = 0; - drflac_uint64 runningGranulePosition = 0; - drflac_uint64 runningFrameBytePos = oggbs->currentBytePos; // <-- Points to the OggS identifier. + runningGranulePosition = 0; + runningFrameBytePos = oggbs->currentBytePos; /* <-- Points to the OggS identifier. */ 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... + 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*pFlac->channels >= sampleIndex) { - break; // The sample is somewhere in the previous page. + 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? + /* + 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? + if ((firstBytesInPage[0] == 0xFF) && (firstBytesInPage[1] & 0xFC) == 0xF8) { /* <-- Does the page begin with a frame's sync code? */ runningGranulePosition = oggbs->currentPageHeader.granulePosition*pFlac->channels; } @@ -5625,11 +5956,12 @@ drflac_bool32 drflac_ogg__seek_to_sample(drflac* pFlac, drflac_uint64 sampleInde } } - - // 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. + /* + 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; } @@ -5637,66 +5969,75 @@ drflac_bool32 drflac_ogg__seek_to_sample(drflac* pFlac, drflac_uint64 sampleInde 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. - drflac_uint64 runningSampleCount = runningGranulePosition; + /* + 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. + */ + runningSampleCount = 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. + /* + 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 firstSampleInFrame = 0; + drflac_uint64 lastSampleInFrame = 0; + drflac_uint64 sampleCountInThisFrame; + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFrame.header)) { return DRFLAC_FALSE; } - drflac_uint64 firstSampleInFrame = 0; - drflac_uint64 lastSampleInFrame = 0; drflac__get_current_frame_sample_range(pFlac, &firstSampleInFrame, &lastSampleInFrame); - drflac_uint64 sampleCountInThisFrame = (lastSampleInFrame - firstSampleInFrame) + 1; + sampleCountInThisFrame = (lastSampleInFrame - firstSampleInFrame) + 1; if (sampleIndex < (runningSampleCount + sampleCountInThisFrame)) { - // 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. + /* + 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_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 samplesToDecode = (size_t)(sampleIndex - runningSampleCount); // <-- Safe cast because the maximum number of samples in a frame is 65535. + /* The frame is valid. We just need to skip over some samples to ensure it's sample-exact. */ + drflac_uint64 samplesToDecode = (size_t)(sampleIndex - runningSampleCount); /* <-- Safe cast because the maximum number of samples in a frame is 65535. */ if (samplesToDecode == 0) { return DRFLAC_TRUE; } - return drflac__seek_forward_by_samples(pFlac, samplesToDecode) == samplesToDecode; // <-- If this fails, something bad has happened (it should never fail). + return drflac__seek_forward_by_samples(pFlac, samplesToDecode) == samplesToDecode; /* <-- 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. + 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. + /* + 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) { runningSampleCount += sampleCountInThisFrame; } else { if (result == DRFLAC_CRC_MISMATCH) { - continue; // CRC mismatch. Pretend this frame never existed. + continue; /* CRC mismatch. Pretend this frame never existed. */ } else { return DRFLAC_FALSE; } @@ -5708,45 +6049,48 @@ drflac_bool32 drflac_ogg__seek_to_sample(drflac* pFlac, drflac_uint64 sampleInde 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) { - // Pre: The bit stream should be sitting just past the 4-byte OggS capture pattern. + 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. - drflac_ogg_page_header header; - - drflac_uint32 crc32 = DRFLAC_OGG_CAPTURE_PATTERN_CRC32; - drflac_uint32 bytesRead = 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 (;;) { - // Break if we're past the beginning of stream page. + 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. - int 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... + /* 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... + /* Increasingly more likely to be a FLAC page... */ drflac_uint8 sig[4]; if (onRead(pUserData, sig, 4) != 4) { return DRFLAC_FALSE; @@ -5754,29 +6098,32 @@ drflac_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_pro bytesRemainingInPage -= 4; if (sig[0] == 'F' && sig[1] == 'L' && sig[2] == 'A' && sig[3] == 'C') { - // Almost certainly a FLAC page... + /* Almost certainly a FLAC page... */ drflac_uint8 mappingVersion[2]; if (onRead(pUserData, mappingVersion, 2) != 2) { return DRFLAC_FALSE; } if (mappingVersion[0] != 1) { - return DRFLAC_FALSE; // Only supporting version 1.x of the Ogg mapping. + return DRFLAC_FALSE; /* Only supporting version 1.x of the Ogg mapping. */ } - // The next 2 bytes are the non-audio packets, not including this one. We don't care about this because we're going to - // be handling it in a generic way based on the serial number and packet types. + /* + The next 2 bytes are the non-audio packets, not including this one. We don't care about this because we're going to + be handling it in a generic way based on the serial number and packet types. + */ if (!onSeek(pUserData, 2, drflac_seek_origin_current)) { return DRFLAC_FALSE; } - // Expecting the native FLAC signature "fLaC". + /* Expecting the native FLAC signature "fLaC". */ if (onRead(pUserData, sig, 4) != 4) { return DRFLAC_FALSE; } if (sig[0] == 'f' && sig[1] == 'L' && sig[2] == 'a' && sig[3] == 'C') { - // The remaining data in the page should be the STREAMINFO block. + /* The remaining data in the page should be the STREAMINFO block. */ + drflac_streaminfo streaminfo; drflac_uint8 isLastBlock; drflac_uint8 blockType; drflac_uint32 blockSize; @@ -5785,12 +6132,11 @@ drflac_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_pro } if (blockType != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) { - return DRFLAC_FALSE; // Invalid block type. First block must be the STREAMINFO block. + return DRFLAC_FALSE; /* Invalid block type. First block must be the STREAMINFO block. */ } - drflac_streaminfo streaminfo; if (drflac__read_streaminfo(onRead, pUserData, &streaminfo)) { - // Success! + /* Success! */ pInit->hasStreamInfoBlock = DRFLAC_TRUE; pInit->sampleRate = streaminfo.sampleRate; pInit->channels = streaminfo.channels; @@ -5809,26 +6155,26 @@ drflac_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_pro } pInit->runningFilePos += pageBodySize; - pInit->oggFirstBytePos = pInit->runningFilePos - 79; // Subtracting 79 will place us right on top of the "OggS" identifier of the FLAC bos page. + pInit->oggFirstBytePos = pInit->runningFilePos - 79; /* Subtracting 79 will place us right on top of the "OggS" identifier of the FLAC bos page. */ pInit->oggSerial = header.serialNumber; pInit->oggBosHeader = header; break; } else { - // Failed to read STREAMINFO block. Aww, so close... + /* Failed to read STREAMINFO block. Aww, so close... */ return DRFLAC_FALSE; } } else { - // Invalid file. + /* Invalid file. */ return DRFLAC_FALSE; } } else { - // Not a FLAC header. Skip it. + /* Not a FLAC header. Skip it. */ if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) { return DRFLAC_FALSE; } } } else { - // Not a FLAC header. Seek past the entire page and move on to the next. + /* Not a FLAC header. Seek past the entire page and move on to the next. */ if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) { return DRFLAC_FALSE; } @@ -5842,24 +6188,28 @@ drflac_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_pro pInit->runningFilePos += pageBodySize; - // Read the header of the next page. + /* Read the header of the next page. */ if (drflac_ogg__read_page_header(onRead, pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) { return DRFLAC_FALSE; } pInit->runningFilePos += bytesRead; } - - // If we get here it means we found a FLAC audio stream. We should be sitting on the first byte of the header of the next page. The next - // packets in the FLAC logical stream contain the metadata. The only thing left to do in the initialization phase for Ogg is to create the - // Ogg bistream object. - pInit->hasMetadataBlocks = DRFLAC_TRUE; // <-- Always have at least VORBIS_COMMENT metadata block. + /* + If we get here it means we found a FLAC audio stream. We should be sitting on the first byte of the header of the next page. The next + packets in the FLAC logical stream contain the metadata. The only thing left to do in the initialization phase for Ogg is to create the + Ogg bistream object. + */ + pInit->hasMetadataBlocks = DRFLAC_TRUE; /* <-- Always have at least VORBIS_COMMENT metadata block. */ return DRFLAC_TRUE; } #endif drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD) { + drflac_bool32 relaxed; + drflac_uint8 id[4]; + if (pInit == NULL || onRead == NULL || onSeek == NULL) { return DRFLAC_FALSE; } @@ -5878,27 +6228,28 @@ drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onR drflac__reset_cache(&pInit->bs); - // If the container is explicitly defined then we can try opening in relaxed mode. - drflac_bool32 relaxed = container != drflac_container_unknown; + /* If the container is explicitly defined then we can try opening in relaxed mode. */ + relaxed = container != drflac_container_unknown; - drflac_uint8 id[4]; - - // Skip over any ID3 tags. + /* Skip over any ID3 tags. */ for (;;) { if (onRead(pUserData, id, 4) != 4) { - return DRFLAC_FALSE; // Ran out of data. + return DRFLAC_FALSE; /* Ran out of data. */ } pInit->runningFilePos += 4; if (id[0] == 'I' && id[1] == 'D' && id[2] == '3') { drflac_uint8 header[6]; + drflac_uint8 flags; + drflac_uint32 headerSize; + if (onRead(pUserData, header, 6) != 6) { - return DRFLAC_FALSE; // Ran out of data. + return DRFLAC_FALSE; /* Ran out of data. */ } pInit->runningFilePos += 6; - drflac_uint8 flags = header[1]; - drflac_uint32 headerSize; + flags = header[1]; + drflac_copy_memory(&headerSize, header+2, 4); headerSize = drflac__unsynchsafe_32(drflac__be2host_32(headerSize)); if (flags & 0x10) { @@ -5906,7 +6257,7 @@ drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onR } if (!onSeek(pUserData, headerSize, drflac_seek_origin_current)) { - return DRFLAC_FALSE; // Failed to seek past the tag. + return DRFLAC_FALSE; /* Failed to seek past the tag. */ } pInit->runningFilePos += headerSize; } else { @@ -5923,7 +6274,7 @@ drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onR } #endif - // If we get here it means we likely don't have a header. Try opening in relaxed mode, if applicable. + /* If we get here it means we likely don't have a header. Try opening in relaxed mode, if applicable. */ if (relaxed) { if (container == drflac_container_native) { return drflac__init_private__native(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed); @@ -5935,7 +6286,7 @@ drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onR #endif } - // Unsupported container. + /* Unsupported container. */ return DRFLAC_FALSE; } @@ -5959,48 +6310,62 @@ void drflac__init_from_info(drflac* pFlac, drflac_init_info* pInit) 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) { + drflac_init_info init; + drflac_uint32 allocationSize; + drflac_uint32 wholeSIMDVectorCountPerChannel; + drflac_uint32 decodedSamplesAllocationSize; +#ifndef DR_FLAC_NO_OGG + drflac_uint32 oggbsAllocationSize; + drflac_oggbs oggbs; +#endif + drflac_uint64 firstFramePos; + drflac_uint64 seektablePos; + drflac_uint32 seektableSize; + drflac* pFlac; + #ifndef DRFLAC_NO_CPUID - // CPU support first. + /* CPU support first. */ drflac__init_cpu_caps(); #endif - drflac_init_info init; if (!drflac__init_private(&init, onRead, onSeek, onMeta, container, pUserData, pUserDataMD)) { return NULL; } - // 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. - drflac_uint32 allocationSize = sizeof(drflac); + /* + 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. - drflac_uint32 wholeSIMDVectorCountPerChannel; + /* + 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.maxBlockSize+DRFLAC_LEADING_SAMPLES) % (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))) == 0) { wholeSIMDVectorCountPerChannel = ((init.maxBlockSize+DRFLAC_LEADING_SAMPLES) / (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))); } else { wholeSIMDVectorCountPerChannel = ((init.maxBlockSize+DRFLAC_LEADING_SAMPLES) / (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))) + 1; } - drflac_uint32 decodedSamplesAllocationSize = wholeSIMDVectorCountPerChannel * DRFLAC_MAX_SIMD_VECTOR_SIZE * init.channels; + 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. + 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. - drflac_uint32 oggbsAllocationSize = 0; + /* There's additional data required for Ogg streams. */ + oggbsAllocationSize = 0; if (init.container == drflac_container_ogg) { oggbsAllocationSize = sizeof(drflac_oggbs); allocationSize += oggbsAllocationSize; } - drflac_oggbs oggbs; drflac_zero_memory(&oggbs, sizeof(oggbs)); if (init.container == drflac_container_ogg) { oggbs.onRead = onRead; @@ -6014,12 +6379,14 @@ drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_p } #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. - drflac_uint64 firstFramePos = 42; // <-- We know we are at byte 42 at this point. - drflac_uint64 seektablePos = 0; - drflac_uint32 seektableSize = 0; + /* + 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; @@ -6041,7 +6408,7 @@ drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_p } - drflac* pFlac = (drflac*)DRFLAC_MALLOC(allocationSize); + pFlac = (drflac*)DRFLAC_MALLOC(allocationSize); drflac__init_from_info(pFlac, &init); pFlac->pDecodedSamples = (drflac_int32*)drflac_align((size_t)pFlac->pExtraData, DRFLAC_MAX_SIMD_VECTOR_SIZE); @@ -6050,7 +6417,7 @@ drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_p drflac_oggbs* pInternalOggbs = (drflac_oggbs*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize + seektableSize); *pInternalOggbs = oggbs; - // The Ogg bistream needs to be layered on top of the original bitstream. + /* 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; @@ -6060,7 +6427,7 @@ drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_p pFlac->firstFramePos = 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. + /* 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) { @@ -6070,33 +6437,34 @@ drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_p else #endif { - // If we have a seektable we need to load it now, making sure we move back to where we were previously. + /* 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); - // Seek to the seektable, then just read directly into our seektable buffer. + /* 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. - for (drflac_uint32 iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) { + /* Endian swap. */ + drflac_uint32 iSeekpoint; + for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) { pFlac->pSeekpoints[iSeekpoint].firstSample = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].firstSample); pFlac->pSeekpoints[iSeekpoint].frameOffset = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].frameOffset); pFlac->pSeekpoints[iSeekpoint].sampleCount = drflac__be2host_16(pFlac->pSeekpoints[iSeekpoint].sampleCount); } } else { - // Failed to read the seektable. Pretend we don't have one. + /* 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. + /* 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->firstFramePos, drflac_seek_origin_start)) { DRFLAC_FREE(pFlac); return NULL; } } else { - // Failed to seek to the seektable. Ominous sign, but for now we can just pretend we don't have one. + /* 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; } @@ -6104,9 +6472,10 @@ drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_p } - - // 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 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->currentFrame.header = init.firstFrameHeader; do @@ -6144,7 +6513,7 @@ static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t byt static drflac_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin) { - drflac_assert(offset >= 0); // <-- Never seek backwards. + drflac_assert(offset >= 0); /* <-- Never seek backwards. */ return fseek((FILE*)pUserData, offset, (origin == drflac_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; } @@ -6169,14 +6538,17 @@ static FILE* drflac__fopen(const char* filename) drflac* drflac_open_file(const char* filename) { - FILE* file = drflac__fopen(filename); - if (file == NULL) { + drflac* pFlac; + FILE* pFile; + + pFile = drflac__fopen(filename); + if (pFile == NULL) { return NULL; } - drflac* pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)file); + pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)pFile); if (pFlac == NULL) { - fclose(file); + fclose(pFile); return NULL; } @@ -6185,28 +6557,33 @@ drflac* drflac_open_file(const char* filename) drflac* drflac_open_file_with_metadata(const char* filename, drflac_meta_proc onMeta, void* pUserData) { - FILE* file = drflac__fopen(filename); - if (file == NULL) { + drflac* pFlac; + FILE* pFile; + + pFile = drflac__fopen(filename); + if (pFile == NULL) { return NULL; } - drflac* pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, drflac_container_unknown, (void*)file, pUserData); + pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData); if (pFlac == NULL) { - fclose(file); + fclose(pFile); return pFlac; } return pFlac; } -#endif //DR_FLAC_NO_STDIO +#endif /* DR_FLAC_NO_STDIO */ static size_t drflac__on_read_memory(void* pUserData, void* bufferOut, size_t bytesToRead) { drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData; + size_t bytesRemaining; + drflac_assert(memoryStream != NULL); drflac_assert(memoryStream->dataSize >= memoryStream->currentReadPos); - size_t bytesRemaining = memoryStream->dataSize - memoryStream->currentReadPos; + bytesRemaining = memoryStream->dataSize - memoryStream->currentReadPos; if (bytesToRead > bytesRemaining) { bytesToRead = bytesRemaining; } @@ -6222,8 +6599,9 @@ static size_t drflac__on_read_memory(void* pUserData, void* bufferOut, size_t by static drflac_bool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_seek_origin origin) { drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData; + drflac_assert(memoryStream != NULL); - drflac_assert(offset >= 0); // <-- Never seek backwards. + drflac_assert(offset >= 0); /* <-- Never seek backwards. */ if (offset > (drflac_int64)memoryStream->dataSize) { return DRFLAC_FALSE; @@ -6233,13 +6611,13 @@ static drflac_bool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_ if (memoryStream->currentReadPos + offset <= memoryStream->dataSize) { memoryStream->currentReadPos += offset; } else { - return DRFLAC_FALSE; // Trying to seek too far forward. + return DRFLAC_FALSE; /* Trying to seek too far forward. */ } } else { if ((drflac_uint32)offset <= memoryStream->dataSize) { memoryStream->currentReadPos = offset; } else { - return DRFLAC_FALSE; // Trying to seek too far forward. + return DRFLAC_FALSE; /* Trying to seek too far forward. */ } } @@ -6249,17 +6627,19 @@ static drflac_bool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_ drflac* drflac_open_memory(const void* data, size_t dataSize) { drflac__memory_stream memoryStream; + drflac* pFlac; + memoryStream.data = (const unsigned char*)data; memoryStream.dataSize = dataSize; memoryStream.currentReadPos = 0; - drflac* pFlac = drflac_open(drflac__on_read_memory, drflac__on_seek_memory, &memoryStream); + pFlac = drflac_open(drflac__on_read_memory, drflac__on_seek_memory, &memoryStream); if (pFlac == NULL) { return NULL; } pFlac->memoryStream = memoryStream; - // This is an awful hack... + /* This is an awful hack... */ #ifndef DR_FLAC_NO_OGG if (pFlac->container == drflac_container_ogg) { @@ -6278,17 +6658,19 @@ drflac* drflac_open_memory(const void* data, size_t dataSize) drflac* drflac_open_memory_with_metadata(const void* data, size_t dataSize, drflac_meta_proc onMeta, void* pUserData) { drflac__memory_stream memoryStream; + drflac* pFlac; + memoryStream.data = (const unsigned char*)data; memoryStream.dataSize = dataSize; memoryStream.currentReadPos = 0; - drflac* pFlac = drflac_open_with_metadata_private(drflac__on_read_memory, drflac__on_seek_memory, onMeta, drflac_container_unknown, &memoryStream, pUserData); + pFlac = drflac_open_with_metadata_private(drflac__on_read_memory, drflac__on_seek_memory, onMeta, drflac_container_unknown, &memoryStream, pUserData); if (pFlac == NULL) { return NULL; } pFlac->memoryStream = memoryStream; - // This is an awful hack... + /* This is an awful hack... */ #ifndef DR_FLAC_NO_OGG if (pFlac->container == drflac_container_ogg) { @@ -6331,17 +6713,20 @@ void drflac_close(drflac* pFlac) } #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 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. + /* 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_assert(pFlac->bs.onRead == drflac__on_read_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); } @@ -6355,21 +6740,20 @@ void drflac_close(drflac* pFlac) drflac_uint64 drflac__read_s32__misaligned(drflac* pFlac, drflac_uint64 samplesToRead, drflac_int32* bufferOut) { unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment); + drflac_uint64 samplesRead; - // We should never be calling this when the number of samples to read is >= the sample count. + /* We should never be calling this when the number of samples to read is >= the sample count. */ drflac_assert(samplesToRead < channelCount); drflac_assert(pFlac->currentFrame.samplesRemaining > 0 && samplesToRead <= pFlac->currentFrame.samplesRemaining); - - drflac_uint64 samplesRead = 0; + samplesRead = 0; while (samplesToRead > 0) { drflac_uint64 totalSamplesInFrame = pFlac->currentFrame.header.blockSize * channelCount; drflac_uint64 samplesReadFromFrameSoFar = totalSamplesInFrame - pFlac->currentFrame.samplesRemaining; drflac_uint64 channelIndex = samplesReadFromFrameSoFar % channelCount; - drflac_uint64 nextSampleInFrame = samplesReadFromFrameSoFar / channelCount; - int decodedSample = 0; + switch (pFlac->currentFrame.header.channelAssignment) { case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE: @@ -6420,7 +6804,6 @@ drflac_uint64 drflac__read_s32__misaligned(drflac* pFlac, drflac_uint64 samplesT } break; } - decodedSample <<= (32 - pFlac->bitsPerSample); if (bufferOut) { @@ -6437,7 +6820,9 @@ drflac_uint64 drflac__read_s32__misaligned(drflac* pFlac, drflac_uint64 samplesT drflac_uint64 drflac_read_s32(drflac* pFlac, drflac_uint64 samplesToRead, drflac_int32* bufferOut) { - // Note that is allowed to be null, in which case this will act like a seek. + drflac_uint64 samplesRead; + + /* Note that is allowed to be null, in which case this will act like a seek. */ if (pFlac == NULL || samplesToRead == 0) { return 0; } @@ -6446,22 +6831,24 @@ drflac_uint64 drflac_read_s32(drflac* pFlac, drflac_uint64 samplesToRead, drflac return drflac__seek_forward_by_samples(pFlac, samplesToRead); } - - drflac_uint64 samplesRead = 0; + samplesRead = 0; while (samplesToRead > 0) { - // If we've run out of samples in this frame, go to the next. + /* If we've run out of samples in this frame, go to the next. */ if (pFlac->currentFrame.samplesRemaining == 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. + break; /* Couldn't read the next frame, so just break from the loop and return. */ } } else { - // Here is where we grab the samples and interleave them. - + /* Here is where we grab the samples and interleave them. */ unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment); drflac_uint64 totalSamplesInFrame = pFlac->currentFrame.header.blockSize * channelCount; drflac_uint64 samplesReadFromFrameSoFar = totalSamplesInFrame - pFlac->currentFrame.samplesRemaining; - drflac_uint64 misalignedSampleCount = samplesReadFromFrameSoFar % channelCount; + drflac_uint64 alignedSampleCountPerChannel; + drflac_uint64 firstAlignedSampleInFrame; + unsigned int unusedBitsPerSample; + drflac_uint64 alignedSamplesRead; + if (misalignedSampleCount > 0) { drflac_uint64 misalignedSamplesRead = drflac__read_s32__misaligned(pFlac, misalignedSampleCount, bufferOut); samplesRead += misalignedSamplesRead; @@ -6472,22 +6859,23 @@ drflac_uint64 drflac_read_s32(drflac* pFlac, drflac_uint64 samplesToRead, drflac } - drflac_uint64 alignedSampleCountPerChannel = samplesToRead / channelCount; + alignedSampleCountPerChannel = samplesToRead / channelCount; if (alignedSampleCountPerChannel > pFlac->currentFrame.samplesRemaining / channelCount) { alignedSampleCountPerChannel = pFlac->currentFrame.samplesRemaining / channelCount; } - drflac_uint64 firstAlignedSampleInFrame = samplesReadFromFrameSoFar / channelCount; - unsigned int unusedBitsPerSample = 32 - pFlac->bitsPerSample; + firstAlignedSampleInFrame = samplesReadFromFrameSoFar / channelCount; + unusedBitsPerSample = 32 - pFlac->bitsPerSample; switch (pFlac->currentFrame.header.channelAssignment) { case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE: { + drflac_uint64 i; const drflac_int32* pDecodedSamples0 = pFlac->currentFrame.subframes[0].pDecodedSamples + firstAlignedSampleInFrame; const drflac_int32* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame; - for (drflac_uint64 i = 0; i < alignedSampleCountPerChannel; ++i) { + for (i = 0; i < alignedSampleCountPerChannel; ++i) { int left = pDecodedSamples0[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample); int side = pDecodedSamples1[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample); int right = left - side; @@ -6499,10 +6887,11 @@ drflac_uint64 drflac_read_s32(drflac* pFlac, drflac_uint64 samplesToRead, drflac case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE: { + drflac_uint64 i; const drflac_int32* pDecodedSamples0 = pFlac->currentFrame.subframes[0].pDecodedSamples + firstAlignedSampleInFrame; const drflac_int32* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame; - for (drflac_uint64 i = 0; i < alignedSampleCountPerChannel; ++i) { + for (i = 0; i < alignedSampleCountPerChannel; ++i) { int side = pDecodedSamples0[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample); int right = pDecodedSamples1[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample); int left = right + side; @@ -6514,10 +6903,11 @@ drflac_uint64 drflac_read_s32(drflac* pFlac, drflac_uint64 samplesToRead, drflac case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE: { + drflac_uint64 i; const drflac_int32* pDecodedSamples0 = pFlac->currentFrame.subframes[0].pDecodedSamples + firstAlignedSampleInFrame; const drflac_int32* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame; - for (drflac_uint64 i = 0; i < alignedSampleCountPerChannel; ++i) { + for (i = 0; i < alignedSampleCountPerChannel; ++i) { int mid = pDecodedSamples0[i] << pFlac->currentFrame.subframes[0].wastedBitsPerSample; int side = pDecodedSamples1[i] << pFlac->currentFrame.subframes[1].wastedBitsPerSample; @@ -6531,22 +6921,25 @@ drflac_uint64 drflac_read_s32(drflac* pFlac, drflac_uint64 samplesToRead, drflac case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT: default: { - if (pFlac->currentFrame.header.channelAssignment == 1) // 1 = Stereo + if (pFlac->currentFrame.header.channelAssignment == 1) /* 1 = Stereo */ { - // Stereo optimized inner loop unroll. + /* Stereo optimized inner loop unroll. */ + drflac_uint64 i; const drflac_int32* pDecodedSamples0 = pFlac->currentFrame.subframes[0].pDecodedSamples + firstAlignedSampleInFrame; const drflac_int32* pDecodedSamples1 = pFlac->currentFrame.subframes[1].pDecodedSamples + firstAlignedSampleInFrame; - for (drflac_uint64 i = 0; i < alignedSampleCountPerChannel; ++i) { + for (i = 0; i < alignedSampleCountPerChannel; ++i) { bufferOut[i*2+0] = pDecodedSamples0[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample); bufferOut[i*2+1] = pDecodedSamples1[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample); } } else { - // Generic interleaving. - for (drflac_uint64 i = 0; i < alignedSampleCountPerChannel; ++i) { - for (unsigned int j = 0; j < channelCount; ++j) { + /* Generic interleaving. */ + drflac_uint64 i; + for (i = 0; i < alignedSampleCountPerChannel; ++i) { + unsigned int j; + for (j = 0; j < channelCount; ++j) { bufferOut[(i*channelCount)+j] = (pFlac->currentFrame.subframes[j].pDecodedSamples[firstAlignedSampleInFrame + i]) << (unusedBitsPerSample + pFlac->currentFrame.subframes[j].wastedBitsPerSample); } } @@ -6554,7 +6947,7 @@ drflac_uint64 drflac_read_s32(drflac* pFlac, drflac_uint64 samplesToRead, drflac } break; } - drflac_uint64 alignedSamplesRead = alignedSampleCountPerChannel * channelCount; + alignedSamplesRead = alignedSampleCountPerChannel * channelCount; samplesRead += alignedSamplesRead; samplesReadFromFrameSoFar += alignedSamplesRead; bufferOut += alignedSamplesRead; @@ -6563,7 +6956,7 @@ drflac_uint64 drflac_read_s32(drflac* pFlac, drflac_uint64 samplesToRead, drflac pFlac->currentFrame.samplesRemaining -= (unsigned int)alignedSamplesRead; - // At this point we may still have some excess samples left to read. + /* At this point we may still have some excess samples left to read. */ if (samplesToRead > 0 && pFlac->currentFrame.samplesRemaining > 0) { drflac_uint64 excessSamplesRead = 0; if (samplesToRead < pFlac->currentFrame.samplesRemaining) { @@ -6588,7 +6981,7 @@ drflac_uint64 drflac_read_pcm_frames_s32(drflac* pFlac, drflac_uint64 framesToRe { #if defined(_MSC_VER) && !defined(__clang__) #pragma warning(push) - #pragma warning(disable:4996) // was declared deprecated + #pragma warning(disable:4996) /* was declared deprecated */ #elif defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" @@ -6604,26 +6997,27 @@ drflac_uint64 drflac_read_pcm_frames_s32(drflac* pFlac, drflac_uint64 framesToRe drflac_uint64 drflac_read_s16(drflac* pFlac, drflac_uint64 samplesToRead, drflac_int16* pBufferOut) { - // This reads samples in 2 passes and can probably be optimized. + /* This reads samples in 2 passes and can probably be optimized. */ drflac_uint64 totalSamplesRead = 0; #if defined(_MSC_VER) && !defined(__clang__) #pragma warning(push) - #pragma warning(disable:4996) // was declared deprecated + #pragma warning(disable:4996) /* was declared deprecated */ #elif defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif while (samplesToRead > 0) { + drflac_uint64 i; drflac_int32 samples32[4096]; drflac_uint64 samplesJustRead = drflac_read_s32(pFlac, (samplesToRead > 4096) ? 4096 : samplesToRead, samples32); if (samplesJustRead == 0) { - break; // Reached the end. + break; /* Reached the end. */ } - // s32 -> s16 - for (drflac_uint64 i = 0; i < samplesJustRead; ++i) { + /* s32 -> s16 */ + for (i = 0; i < samplesJustRead; ++i) { pBufferOut[i] = (drflac_int16)(samples32[i] >> 16); } @@ -6643,19 +7037,21 @@ drflac_uint64 drflac_read_s16(drflac* pFlac, drflac_uint64 samplesToRead, drflac drflac_uint64 drflac_read_pcm_frames_s16(drflac* pFlac, drflac_uint64 framesToRead, drflac_int16* pBufferOut) { - // This reads samples in 2 passes and can probably be optimized. + /* This reads samples in 2 passes and can probably be optimized. */ drflac_uint64 totalPCMFramesRead = 0; while (framesToRead > 0) { + drflac_uint64 iFrame; drflac_int32 samples32[4096]; drflac_uint64 framesJustRead = drflac_read_pcm_frames_s32(pFlac, (framesToRead > 4096/pFlac->channels) ? 4096/pFlac->channels : framesToRead, samples32); if (framesJustRead == 0) { - break; // Reached the end. + break; /* Reached the end. */ } - // s32 -> s16 - for (drflac_uint64 iFrame = 0; iFrame < framesJustRead; ++iFrame) { - for (drflac_uint32 iChannel = 0; iChannel < pFlac->channels; ++iChannel) { + /* s32 -> s16 */ + for (iFrame = 0; iFrame < framesJustRead; ++iFrame) { + drflac_uint32 iChannel; + for (iChannel = 0; iChannel < pFlac->channels; ++iChannel) { drflac_uint64 iSample = iFrame*pFlac->channels + iChannel; pBufferOut[iSample] = (drflac_int16)(samples32[iSample] >> 16); } @@ -6672,26 +7068,27 @@ drflac_uint64 drflac_read_pcm_frames_s16(drflac* pFlac, drflac_uint64 framesToRe drflac_uint64 drflac_read_f32(drflac* pFlac, drflac_uint64 samplesToRead, float* pBufferOut) { - // This reads samples in 2 passes and can probably be optimized. + /* This reads samples in 2 passes and can probably be optimized. */ drflac_uint64 totalSamplesRead = 0; #if defined(_MSC_VER) && !defined(__clang__) #pragma warning(push) - #pragma warning(disable:4996) // was declared deprecated + #pragma warning(disable:4996) /* was declared deprecated */ #elif defined(__GNUC__) || defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif while (samplesToRead > 0) { + drflac_uint64 i; drflac_int32 samples32[4096]; drflac_uint64 samplesJustRead = drflac_read_s32(pFlac, (samplesToRead > 4096) ? 4096 : samplesToRead, samples32); if (samplesJustRead == 0) { - break; // Reached the end. + break; /* Reached the end. */ } - // s32 -> f32 - for (drflac_uint64 i = 0; i < samplesJustRead; ++i) { + /* s32 -> f32 */ + for (i = 0; i < samplesJustRead; ++i) { pBufferOut[i] = (float)(samples32[i] / 2147483648.0); } @@ -6712,7 +7109,8 @@ drflac_uint64 drflac_read_f32(drflac* pFlac, drflac_uint64 samplesToRead, float* #if 0 static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_int32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { - for (drflac_uint64 i = 0; i < frameCount; ++i) { + drflac_uint64 i; + for (i = 0; i < frameCount; ++i) { int left = pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample); int side = pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample); int right = left - side; @@ -6725,13 +7123,14 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__referenc static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_int32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { + drflac_uint64 i; drflac_uint64 frameCount4 = frameCount >> 2; float factor = 1 / 2147483648.0; drflac_int32 shift0 = unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample; drflac_int32 shift1 = unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample; - for (drflac_uint64 i = 0; i < frameCount4; ++i) { + for (i = 0; i < frameCount4; ++i) { drflac_int32 left0 = pInputSamples0[i*4+0] << shift0; drflac_int32 left1 = pInputSamples0[i*4+1] << shift0; drflac_int32 left2 = pInputSamples0[i*4+2] << shift0; @@ -6757,7 +7156,7 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__scalar(d pOutputSamples[i*8+7] = right3 * factor; } - for (drflac_uint64 i = (frameCount4 << 2); i < frameCount; ++i) { + for (i = (frameCount4 << 2); i < frameCount; ++i) { int left = pInputSamples0[i] << shift0; int side = pInputSamples1[i] << shift1; int right = left - side; @@ -6770,15 +7169,21 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__scalar(d #if defined(DRFLAC_SUPPORT_SSE2) static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_int32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { + drflac_uint64 frameCount4; + __m128 factor; + int shift0; + int shift1; + drflac_uint64 i; + drflac_assert(pFlac->bitsPerSample <= 24); - drflac_uint64 frameCount4 = frameCount >> 2; + frameCount4 = frameCount >> 2; - __m128 factor = _mm_set1_ps(1.0f / 8388608.0f); - int shift0 = (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample) - 8; - int shift1 = (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample) - 8; + factor = _mm_set1_ps(1.0f / 8388608.0f); + shift0 = (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample) - 8; + shift1 = (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample) - 8; - for (drflac_uint64 i = 0; i < frameCount4; ++i) { + for (i = 0; i < frameCount4; ++i) { __m128i inputSample0 = _mm_loadu_si128((const __m128i*)pInputSamples0 + i); __m128i inputSample1 = _mm_loadu_si128((const __m128i*)pInputSamples1 + i); @@ -6798,7 +7203,7 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__sse2(drf pOutputSamples[i*8+7] = ((float*)&rightf)[3]; } - for (drflac_uint64 i = (frameCount4 << 2); i < frameCount; ++i) { + for (i = (frameCount4 << 2); i < frameCount; ++i) { int left = pInputSamples0[i] << shift0; int side = pInputSamples1[i] << shift1; int right = left - side; @@ -6817,7 +7222,7 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side(drflac* p } else #endif { - // Scalar fallback. + /* Scalar fallback. */ #if 0 drflac_read_pcm_frames_f32__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #else @@ -6830,7 +7235,8 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side(drflac* p #if 0 static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_int32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { - for (drflac_uint64 i = 0; i < frameCount; ++i) { + drflac_uint64 i; + for (i = 0; i < frameCount; ++i) { int side = pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample); int right = pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample); int left = right + side; @@ -6843,13 +7249,14 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__referen static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_int32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { + drflac_uint64 i; drflac_uint64 frameCount4 = frameCount >> 2; float factor = 1 / 2147483648.0; drflac_int32 shift0 = unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample; drflac_int32 shift1 = unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample; - for (drflac_uint64 i = 0; i < frameCount4; ++i) { + for (i = 0; i < frameCount4; ++i) { drflac_int32 side0 = pInputSamples0[i*4+0] << shift0; drflac_int32 side1 = pInputSamples0[i*4+1] << shift0; drflac_int32 side2 = pInputSamples0[i*4+2] << shift0; @@ -6875,7 +7282,7 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__scalar( pOutputSamples[i*8+7] = right3 * factor; } - for (drflac_uint64 i = (frameCount4 << 2); i < frameCount; ++i) { + for (i = (frameCount4 << 2); i < frameCount; ++i) { int side = pInputSamples0[i] << shift0; int right = pInputSamples1[i] << shift1; int left = right + side; @@ -6888,15 +7295,21 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__scalar( #if defined(DRFLAC_SUPPORT_SSE2) static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_int32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { + drflac_uint64 frameCount4; + __m128 factor; + int shift0; + int shift1; + drflac_uint64 i; + drflac_assert(pFlac->bitsPerSample <= 24); - drflac_uint64 frameCount4 = frameCount >> 2; + frameCount4 = frameCount >> 2; - __m128 factor = _mm_set1_ps(1.0f / 8388608.0f); - int shift0 = (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample) - 8; - int shift1 = (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample) - 8; + factor = _mm_set1_ps(1.0f / 8388608.0f); + shift0 = (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample) - 8; + shift1 = (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample) - 8; - for (drflac_uint64 i = 0; i < frameCount4; ++i) { + for (i = 0; i < frameCount4; ++i) { __m128i inputSample0 = _mm_loadu_si128((const __m128i*)pInputSamples0 + i); __m128i inputSample1 = _mm_loadu_si128((const __m128i*)pInputSamples1 + i); @@ -6916,7 +7329,7 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__sse2(dr pOutputSamples[i*8+7] = ((float*)&rightf)[3]; } - for (drflac_uint64 i = (frameCount4 << 2); i < frameCount; ++i) { + for (i = (frameCount4 << 2); i < frameCount; ++i) { int side = pInputSamples0[i] << shift0; int right = pInputSamples1[i] << shift1; int left = right + side; @@ -6935,7 +7348,7 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side(drflac* } else #endif { - // Scalar fallback. + /* Scalar fallback. */ #if 0 drflac_read_pcm_frames_f32__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #else @@ -6962,6 +7375,7 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__reference static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_int32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { + drflac_uint64 i; drflac_uint64 frameCount4 = frameCount >> 2; float factor = 1 / 2147483648.0; @@ -6969,7 +7383,16 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__scalar(dr int shift = unusedBitsPerSample; if (shift > 0) { shift -= 1; - for (drflac_uint64 i = 0; i < frameCount4; ++i) { + for (i = 0; i < frameCount4; ++i) { + int temp0L; + int temp1L; + int temp2L; + int temp3L; + int temp0R; + int temp1R; + int temp2R; + int temp3R; + int mid0 = pInputSamples0[i*4+0] << pFlac->currentFrame.subframes[0].wastedBitsPerSample; int mid1 = pInputSamples0[i*4+1] << pFlac->currentFrame.subframes[0].wastedBitsPerSample; int mid2 = pInputSamples0[i*4+2] << pFlac->currentFrame.subframes[0].wastedBitsPerSample; @@ -6985,15 +7408,15 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__scalar(dr mid2 = (((drflac_uint32)mid2) << 1) | (side2 & 0x01); mid3 = (((drflac_uint32)mid3) << 1) | (side3 & 0x01); - int temp0L = ((mid0 + side0) << shift); - int temp1L = ((mid1 + side1) << shift); - int temp2L = ((mid2 + side2) << shift); - int temp3L = ((mid3 + side3) << shift); + temp0L = ((mid0 + side0) << shift); + temp1L = ((mid1 + side1) << shift); + temp2L = ((mid2 + side2) << shift); + temp3L = ((mid3 + side3) << shift); - int temp0R = ((mid0 - side0) << shift); - int temp1R = ((mid1 - side1) << shift); - int temp2R = ((mid2 - side2) << shift); - int temp3R = ((mid3 - side3) << shift); + temp0R = ((mid0 - side0) << shift); + temp1R = ((mid1 - side1) << shift); + temp2R = ((mid2 - side2) << shift); + temp3R = ((mid3 - side3) << shift); pOutputSamples[i*8+0] = (float)(temp0L * factor); pOutputSamples[i*8+1] = (float)(temp0R * factor); @@ -7005,7 +7428,16 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__scalar(dr pOutputSamples[i*8+7] = (float)(temp3R * factor); } } else { - for (drflac_uint64 i = 0; i < frameCount4; ++i) { + for (i = 0; i < frameCount4; ++i) { + int temp0L; + int temp1L; + int temp2L; + int temp3L; + int temp0R; + int temp1R; + int temp2R; + int temp3R; + int mid0 = pInputSamples0[i*4+0] << pFlac->currentFrame.subframes[0].wastedBitsPerSample; int mid1 = pInputSamples0[i*4+1] << pFlac->currentFrame.subframes[0].wastedBitsPerSample; int mid2 = pInputSamples0[i*4+2] << pFlac->currentFrame.subframes[0].wastedBitsPerSample; @@ -7021,15 +7453,15 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__scalar(dr mid2 = (((drflac_uint32)mid2) << 1) | (side2 & 0x01); mid3 = (((drflac_uint32)mid3) << 1) | (side3 & 0x01); - int temp0L = ((mid0 + side0) >> 1); - int temp1L = ((mid1 + side1) >> 1); - int temp2L = ((mid2 + side2) >> 1); - int temp3L = ((mid3 + side3) >> 1); + temp0L = ((mid0 + side0) >> 1); + temp1L = ((mid1 + side1) >> 1); + temp2L = ((mid2 + side2) >> 1); + temp3L = ((mid3 + side3) >> 1); - int temp0R = ((mid0 - side0) >> 1); - int temp1R = ((mid1 - side1) >> 1); - int temp2R = ((mid2 - side2) >> 1); - int temp3R = ((mid3 - side3) >> 1); + temp0R = ((mid0 - side0) >> 1); + temp1R = ((mid1 - side1) >> 1); + temp2R = ((mid2 - side2) >> 1); + temp3R = ((mid3 - side3) >> 1); pOutputSamples[i*8+0] = (float)(temp0L * factor); pOutputSamples[i*8+1] = (float)(temp0R * factor); @@ -7042,7 +7474,7 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__scalar(dr } } - for (drflac_uint64 i = (frameCount4 << 2); i < frameCount; ++i) { + for (i = (frameCount4 << 2); i < frameCount; ++i) { int mid = pInputSamples0[i] << pFlac->currentFrame.subframes[0].wastedBitsPerSample; int side = pInputSamples1[i] << pFlac->currentFrame.subframes[1].wastedBitsPerSample; @@ -7056,16 +7488,21 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__scalar(dr #if defined(DRFLAC_SUPPORT_SSE2) static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_int32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { + drflac_uint64 i; + drflac_uint64 frameCount4; + float factor; + __m128 factor128; + drflac_assert(pFlac->bitsPerSample <= 24); - drflac_uint64 frameCount4 = frameCount >> 2; + frameCount4 = frameCount >> 2; - float factor = 1.0f / 8388608.0f; - __m128 factor128 = _mm_set1_ps(1.0f / 8388608.0f); + factor = 1.0f / 8388608.0f; + factor128 = _mm_set1_ps(1.0f / 8388608.0f); int shift = unusedBitsPerSample - 8; if (shift == 0) { - for (drflac_uint64 i = 0; i < frameCount4; ++i) { + for (i = 0; i < frameCount4; ++i) { __m128i inputSample0 = _mm_loadu_si128((const __m128i*)pInputSamples0 + i); __m128i inputSample1 = _mm_loadu_si128((const __m128i*)pInputSamples1 + i); @@ -7077,7 +7514,7 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__sse2(drfl __m128i tempL = _mm_add_epi32(mid, side); __m128i tempR = _mm_sub_epi32(mid, side); - // Signed bit shift. + /* Signed bit shift. */ tempL = _mm_or_si128(_mm_srli_epi32(tempL, 1), _mm_and_si128(tempL, _mm_set1_epi32(0x80000000))); tempR = _mm_or_si128(_mm_srli_epi32(tempR, 1), _mm_and_si128(tempR, _mm_set1_epi32(0x80000000))); @@ -7094,7 +7531,7 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__sse2(drfl pOutputSamples[i*8+7] = ((float*)&rightf)[3]; } - for (drflac_uint64 i = (frameCount4 << 2); i < frameCount; ++i) { + for (i = (frameCount4 << 2); i < frameCount; ++i) { int mid = pInputSamples0[i] << pFlac->currentFrame.subframes[0].wastedBitsPerSample; int side = pInputSamples1[i] << pFlac->currentFrame.subframes[1].wastedBitsPerSample; @@ -7104,20 +7541,29 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__sse2(drfl pOutputSamples[i*2+1] = (float)(((mid - side) >> 1) * factor); } } else { - for (drflac_uint64 i = 0; i < frameCount4; ++i) { - __m128i inputSample0 = _mm_loadu_si128((const __m128i*)pInputSamples0 + i); - __m128i inputSample1 = _mm_loadu_si128((const __m128i*)pInputSamples1 + i); + for (i = 0; i < frameCount4; ++i) { + __m128i inputSample0; + __m128i inputSample1; + __m128i mid; + __m128i side; + __m128i tempL; + __m128i tempR; + __m128 leftf; + __m128 rightf; - __m128i mid = _mm_slli_epi32(inputSample0, pFlac->currentFrame.subframes[0].wastedBitsPerSample); - __m128i side = _mm_slli_epi32(inputSample1, pFlac->currentFrame.subframes[1].wastedBitsPerSample); + inputSample0 = _mm_loadu_si128((const __m128i*)pInputSamples0 + i); + inputSample1 = _mm_loadu_si128((const __m128i*)pInputSamples1 + i); + + mid = _mm_slli_epi32(inputSample0, pFlac->currentFrame.subframes[0].wastedBitsPerSample); + side = _mm_slli_epi32(inputSample1, pFlac->currentFrame.subframes[1].wastedBitsPerSample); mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01))); - __m128i tempL = _mm_slli_epi32(_mm_srli_epi32(_mm_add_epi32(mid, side), 1), shift); - __m128i tempR = _mm_slli_epi32(_mm_srli_epi32(_mm_sub_epi32(mid, side), 1), shift); + tempL = _mm_slli_epi32(_mm_srli_epi32(_mm_add_epi32(mid, side), 1), shift); + tempR = _mm_slli_epi32(_mm_srli_epi32(_mm_sub_epi32(mid, side), 1), shift); - __m128 leftf = _mm_mul_ps(_mm_cvtepi32_ps(tempL), factor128); - __m128 rightf = _mm_mul_ps(_mm_cvtepi32_ps(tempR), factor128); + leftf = _mm_mul_ps(_mm_cvtepi32_ps(tempL), factor128); + rightf = _mm_mul_ps(_mm_cvtepi32_ps(tempR), factor128); pOutputSamples[i*8+0] = ((float*)&leftf)[0]; pOutputSamples[i*8+1] = ((float*)&rightf)[0]; @@ -7129,7 +7575,7 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__sse2(drfl pOutputSamples[i*8+7] = ((float*)&rightf)[3]; } - for (drflac_uint64 i = (frameCount4 << 2); i < frameCount; ++i) { + for (i = (frameCount4 << 2); i < frameCount; ++i) { int mid = pInputSamples0[i] << pFlac->currentFrame.subframes[0].wastedBitsPerSample; int side = pInputSamples1[i] << pFlac->currentFrame.subframes[1].wastedBitsPerSample; @@ -7151,7 +7597,7 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side(drflac* pF } else #endif { - // Scalar fallback. + /* Scalar fallback. */ #if 0 drflac_read_pcm_frames_f32__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #else @@ -7172,6 +7618,7 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo_ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_int32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { + drflac_uint64 i; drflac_uint64 frameCount4 = frameCount >> 2; float factor = 1 / 2147483648.0; @@ -7179,7 +7626,7 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo_ int shift0 = (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample); int shift1 = (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample); - for (drflac_uint64 i = 0; i < frameCount4; ++i) { + for (i = 0; i < frameCount4; ++i) { int tempL0 = pInputSamples0[i*4+0] << shift0; int tempL1 = pInputSamples0[i*4+1] << shift0; int tempL2 = pInputSamples0[i*4+2] << shift0; @@ -7200,7 +7647,7 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo_ pOutputSamples[i*8+7] = (float)(tempR3 * factor); } - for (drflac_uint64 i = (frameCount4 << 2); i < frameCount; ++i) { + for (i = (frameCount4 << 2); i < frameCount; ++i) { pOutputSamples[i*2+0] = (float)((pInputSamples0[i] << shift0) * factor); pOutputSamples[i*2+1] = (float)((pInputSamples1[i] << shift1) * factor); } @@ -7209,6 +7656,7 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo_ #if defined(DRFLAC_SUPPORT_SSE2) static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_int32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) { + drflac_uint64 i; drflac_uint64 frameCount4 = frameCount >> 2; float factor = 1.0f / 8388608.0f; @@ -7217,7 +7665,7 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo_ int shift0 = (unusedBitsPerSample + pFlac->currentFrame.subframes[0].wastedBitsPerSample) - 8; int shift1 = (unusedBitsPerSample + pFlac->currentFrame.subframes[1].wastedBitsPerSample) - 8; - for (drflac_uint64 i = 0; i < frameCount4; ++i) { + for (i = 0; i < frameCount4; ++i) { __m128i inputSample0 = _mm_loadu_si128((const __m128i*)pInputSamples0 + i); __m128i inputSample1 = _mm_loadu_si128((const __m128i*)pInputSamples1 + i); @@ -7237,7 +7685,7 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo_ pOutputSamples[i*8+7] = ((float*)&f32R)[3]; } - for (drflac_uint64 i = (frameCount4 << 2); i < frameCount; ++i) { + for (i = (frameCount4 << 2); i < frameCount; ++i) { pOutputSamples[i*2+0] = (float)((pInputSamples0[i] << shift0) * factor); pOutputSamples[i*2+1] = (float)((pInputSamples1[i] << shift1) * factor); } @@ -7252,7 +7700,7 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo( } else #endif { - // Scalar fallback. + /* Scalar fallback. */ #if 0 drflac_read_pcm_frames_f32__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); #else @@ -7263,6 +7711,8 @@ static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo( drflac_uint64 drflac_read_pcm_frames_f32(drflac* pFlac, drflac_uint64 framesToRead, float* pBufferOut) { + drflac_uint64 framesRead; + if (pFlac == NULL || framesToRead == 0) { return 0; } @@ -7271,12 +7721,12 @@ drflac_uint64 drflac_read_pcm_frames_f32(drflac* pFlac, drflac_uint64 framesToRe return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead); } - drflac_uint64 framesRead = 0; + framesRead = 0; while (framesToRead > 0) { - // If we've run out of samples in this frame, go to the next. + /* If we've run out of samples in this frame, go to the next. */ if (pFlac->currentFrame.samplesRemaining == 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. + 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->currentFrame.header.channelAssignment); @@ -7284,8 +7734,9 @@ drflac_uint64 drflac_read_pcm_frames_f32(drflac* pFlac, drflac_uint64 framesToRe drflac_uint64 framesReadFromPacketSoFar = totalFramesInPacket - (pFlac->currentFrame.samplesRemaining/channelCount); drflac_uint64 iFirstPCMFrame = framesReadFromPacketSoFar; drflac_int32 unusedBitsPerSample = 32 - pFlac->bitsPerSample; - drflac_uint64 frameCountThisIteration = framesToRead; + drflac_uint64 samplesReadThisIteration; + if (frameCountThisIteration > pFlac->currentFrame.samplesRemaining / channelCount) { frameCountThisIteration = pFlac->currentFrame.samplesRemaining / channelCount; } @@ -7318,15 +7769,17 @@ drflac_uint64 drflac_read_pcm_frames_f32(drflac* pFlac, drflac_uint64 framesToRe } break; } } else { - // Generic interleaving. - for (drflac_uint64 i = 0; i < frameCountThisIteration; ++i) { - for (unsigned int j = 0; j < channelCount; ++j) { + /* Generic interleaving. */ + drflac_uint64 i; + for (i = 0; i < frameCountThisIteration; ++i) { + unsigned int j; + for (j = 0; j < channelCount; ++j) { pBufferOut[(i*channelCount)+j] = (float)(((pFlac->currentFrame.subframes[j].pDecodedSamples[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFrame.subframes[j].wastedBitsPerSample)) / 2147483648.0); } } } - drflac_uint64 samplesReadThisIteration = frameCountThisIteration * channelCount; + samplesReadThisIteration = frameCountThisIteration * channelCount; framesRead += frameCountThisIteration; framesReadFromPacketSoFar += frameCountThisIteration; pBufferOut += samplesReadThisIteration; @@ -7345,8 +7798,10 @@ drflac_bool32 drflac_seek_to_sample(drflac* pFlac, drflac_uint64 sampleIndex) return DRFLAC_FALSE; } - // 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 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->firstFramePos == 0) { return DRFLAC_FALSE; } @@ -7357,14 +7812,14 @@ drflac_bool32 drflac_seek_to_sample(drflac* pFlac, drflac_uint64 sampleIndex) } else { drflac_bool32 wasSuccessful = DRFLAC_FALSE; - // Clamp the sample to the end. + /* Clamp the sample to the end. */ if (sampleIndex >= pFlac->totalSampleCount) { sampleIndex = pFlac->totalSampleCount - 1; } - // If the target sample and the current sample are in the same frame we just move the position forward. + /* If the target sample and the current sample are in the same frame we just move the position forward. */ if (sampleIndex > pFlac->currentSample) { - // Forward. + /* Forward. */ drflac_uint32 offset = (drflac_uint32)(sampleIndex - pFlac->currentSample); if (pFlac->currentFrame.samplesRemaining > offset) { pFlac->currentFrame.samplesRemaining -= offset; @@ -7372,7 +7827,7 @@ drflac_bool32 drflac_seek_to_sample(drflac* pFlac, drflac_uint64 sampleIndex) return DRFLAC_TRUE; } } else { - // Backward. + /* Backward. */ drflac_uint32 offsetAbs = (drflac_uint32)(pFlac->currentSample - sampleIndex); drflac_uint32 currentFrameSampleCount = pFlac->currentFrame.header.blockSize * drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment); drflac_uint32 currentFrameSamplesConsumed = (drflac_uint32)(currentFrameSampleCount - pFlac->currentFrame.samplesRemaining); @@ -7383,8 +7838,10 @@ drflac_bool32 drflac_seek_to_sample(drflac* pFlac, drflac_uint64 sampleIndex) } } - // 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. + /* + 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) { @@ -7393,7 +7850,7 @@ drflac_bool32 drflac_seek_to_sample(drflac* pFlac, drflac_uint64 sampleIndex) else #endif { - // First try seeking via the seek table. If this fails, fall back to a brute force seek which is much slower. + /* First try seeking via the seek table. If this fails, fall back to a brute force seek which is much slower. */ wasSuccessful = drflac__seek_to_sample__seek_table(pFlac, sampleIndex); if (!wasSuccessful) { wasSuccessful = drflac__seek_to_sample__brute_force(pFlac, sampleIndex); @@ -7411,8 +7868,10 @@ drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameInde return DRFLAC_FALSE; } - // 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 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->firstFramePos == 0) { return DRFLAC_FALSE; } @@ -7423,14 +7882,14 @@ drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameInde } else { drflac_bool32 wasSuccessful = DRFLAC_FALSE; - // Clamp the sample to the end. + /* Clamp the sample to the end. */ if (pcmFrameIndex >= pFlac->totalPCMFrameCount) { pcmFrameIndex = pFlac->totalPCMFrameCount - 1; } - // If the target sample and the current sample are in the same frame we just move the position forward. + /* If the target sample and the current sample are in the same frame we just move the position forward. */ if (pcmFrameIndex*pFlac->channels > pFlac->currentSample) { - // Forward. + /* Forward. */ drflac_uint32 offset = (drflac_uint32)(pcmFrameIndex*pFlac->channels - pFlac->currentSample); if (pFlac->currentFrame.samplesRemaining > offset) { pFlac->currentFrame.samplesRemaining -= offset; @@ -7438,7 +7897,7 @@ drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameInde return DRFLAC_TRUE; } } else { - // Backward. + /* Backward. */ drflac_uint32 offsetAbs = (drflac_uint32)(pFlac->currentSample - pcmFrameIndex*pFlac->channels); drflac_uint32 currentFrameSampleCount = pFlac->currentFrame.header.blockSize * drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment); drflac_uint32 currentFrameSamplesConsumed = (drflac_uint32)(currentFrameSampleCount - pFlac->currentFrame.samplesRemaining); @@ -7449,8 +7908,10 @@ drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameInde } } - // 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. + /* + 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) { @@ -7459,7 +7920,7 @@ drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameInde else #endif { - // First try seeking via the seek table. If this fails, fall back to a brute force seek which is much slower. + /* First try seeking via the seek table. If this fails, fall back to a brute force seek which is much slower. */ wasSuccessful = drflac__seek_to_sample__seek_table(pFlac, pcmFrameIndex*pFlac->channels); if (!wasSuccessful) { wasSuccessful = drflac__seek_to_sample__brute_force(pFlac, pcmFrameIndex*pFlac->channels); @@ -7473,7 +7934,7 @@ drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameInde -//// High Level APIs //// +/* High Level APIs */ #if defined(SIZE_MAX) #define DRFLAC_SIZE_MAX SIZE_MAX @@ -7486,29 +7947,33 @@ drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameInde #endif -// Using a macro as the definition of the drflac__full_decode_and_close_*() API family. Sue me. +/* 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); \ \ - type* pSampleData = NULL; \ - drflac_uint64 totalPCMFrameCount = pFlac->totalPCMFrameCount; \ + totalPCMFrameCount = pFlac->totalPCMFrameCount; \ \ if (totalPCMFrameCount == 0) { \ type buffer[4096]; \ - \ + drflac_uint64 pcmFramesRead; \ size_t sampleDataBufferSize = sizeof(buffer); \ + \ pSampleData = (type*)DRFLAC_MALLOC(sampleDataBufferSize); \ if (pSampleData == NULL) { \ goto on_error; \ } \ \ - drflac_uint64 pcmFramesRead; \ 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; \ + \ sampleDataBufferSize *= 2; \ - type* pNewSampleData = (type*)DRFLAC_REALLOC(pSampleData, sampleDataBufferSize); \ + pNewSampleData = (type*)DRFLAC_REALLOC(pSampleData, sampleDataBufferSize); \ if (pNewSampleData == NULL) { \ DRFLAC_FREE(pSampleData); \ goto on_error; \ @@ -7556,12 +8021,19 @@ DRFLAC_DEFINE_FULL_READ_AND_CLOSE(f32, float) 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) { - // Safety. - if (channelsOut) *channelsOut = 0; - if (sampleRateOut) *sampleRateOut = 0; - if (totalPCMFrameCountOut) *totalPCMFrameCountOut = 0; + drflac* pFlac; - drflac* pFlac = drflac_open(onRead, onSeek, pUserData); + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalPCMFrameCountOut) { + *totalPCMFrameCountOut = 0; + } + + pFlac = drflac_open(onRead, onSeek, pUserData); if (pFlac == NULL) { return NULL; } @@ -7571,23 +8043,35 @@ drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drfla drflac_int32* drflac_open_and_decode_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalSampleCountOut) { - // Safety. - if (channelsOut) *channelsOut = 0; - if (sampleRateOut) *sampleRateOut = 0; - if (totalSampleCountOut) *totalSampleCountOut = 0; - unsigned int channels; unsigned int sampleRate; drflac_uint64 totalPCMFrameCount; + drflac_int32* pResult; - drflac_int32* pResult = drflac_open_and_read_pcm_frames_s32(onRead, onSeek, pUserData, &channels, &sampleRate, &totalPCMFrameCount); + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalSampleCountOut) { + *totalSampleCountOut = 0; + } + + pResult = drflac_open_and_read_pcm_frames_s32(onRead, onSeek, pUserData, &channels, &sampleRate, &totalPCMFrameCount); if (pResult == NULL) { return NULL; } - if (channelsOut) *channelsOut = channels; - if (sampleRateOut) *sampleRateOut = sampleRate; - if (totalSampleCountOut) *totalSampleCountOut = totalPCMFrameCount * channels; + if (channelsOut) { + *channelsOut = channels; + } + if (sampleRateOut) { + *sampleRateOut = sampleRate; + } + if (totalSampleCountOut) { + *totalSampleCountOut = totalPCMFrameCount * channels; + } return pResult; } @@ -7596,12 +8080,19 @@ drflac_int32* drflac_open_and_decode_s32(drflac_read_proc onRead, drflac_seek_pr 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) { - // Safety. - if (channelsOut) *channelsOut = 0; - if (sampleRateOut) *sampleRateOut = 0; - if (totalPCMFrameCountOut) *totalPCMFrameCountOut = 0; + drflac* pFlac; - drflac* pFlac = drflac_open(onRead, onSeek, pUserData); + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalPCMFrameCountOut) { + *totalPCMFrameCountOut = 0; + } + + pFlac = drflac_open(onRead, onSeek, pUserData); if (pFlac == NULL) { return NULL; } @@ -7611,23 +8102,35 @@ drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drfla drflac_int16* drflac_open_and_decode_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalSampleCountOut) { - // Safety. - if (channelsOut) *channelsOut = 0; - if (sampleRateOut) *sampleRateOut = 0; - if (totalSampleCountOut) *totalSampleCountOut = 0; - unsigned int channels; unsigned int sampleRate; drflac_uint64 totalPCMFrameCount; + drflac_int16* pResult; - drflac_int16* pResult = drflac_open_and_read_pcm_frames_s16(onRead, onSeek, pUserData, &channels, &sampleRate, &totalPCMFrameCount); + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalSampleCountOut) { + *totalSampleCountOut = 0; + } + + pResult = drflac_open_and_read_pcm_frames_s16(onRead, onSeek, pUserData, &channels, &sampleRate, &totalPCMFrameCount); if (pResult == NULL) { return NULL; } - if (channelsOut) *channelsOut = channels; - if (sampleRateOut) *sampleRateOut = sampleRate; - if (totalSampleCountOut) *totalSampleCountOut = totalPCMFrameCount * channels; + if (channelsOut) { + *channelsOut = channels; + } + if (sampleRateOut) { + *sampleRateOut = sampleRate; + } + if (totalSampleCountOut) { + *totalSampleCountOut = totalPCMFrameCount * channels; + } return pResult; } @@ -7635,12 +8138,19 @@ drflac_int16* drflac_open_and_decode_s16(drflac_read_proc onRead, drflac_seek_pr 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) { - // Safety. - if (channelsOut) *channelsOut = 0; - if (sampleRateOut) *sampleRateOut = 0; - if (totalPCMFrameCountOut) *totalPCMFrameCountOut = 0; + drflac* pFlac; - drflac* pFlac = drflac_open(onRead, onSeek, pUserData); + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalPCMFrameCountOut) { + *totalPCMFrameCountOut = 0; + } + + pFlac = drflac_open(onRead, onSeek, pUserData); if (pFlac == NULL) { return NULL; } @@ -7650,23 +8160,35 @@ float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_ float* drflac_open_and_decode_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalSampleCountOut) { - // Safety. - if (channelsOut) *channelsOut = 0; - if (sampleRateOut) *sampleRateOut = 0; - if (totalSampleCountOut) *totalSampleCountOut = 0; - unsigned int channels; unsigned int sampleRate; drflac_uint64 totalPCMFrameCount; + float* pResult; - float* pResult = drflac_open_and_read_pcm_frames_f32(onRead, onSeek, pUserData, &channels, &sampleRate, &totalPCMFrameCount); + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalSampleCountOut) { + *totalSampleCountOut = 0; + } + + pResult = drflac_open_and_read_pcm_frames_f32(onRead, onSeek, pUserData, &channels, &sampleRate, &totalPCMFrameCount); if (pResult == NULL) { return NULL; } - if (channelsOut) *channelsOut = channels; - if (sampleRateOut) *sampleRateOut = sampleRate; - if (totalSampleCountOut) *totalSampleCountOut = totalPCMFrameCount * channels; + if (channelsOut) { + *channelsOut = channels; + } + if (sampleRateOut) { + *sampleRateOut = sampleRate; + } + if (totalSampleCountOut) { + *totalSampleCountOut = totalPCMFrameCount * channels; + } return pResult; } @@ -7674,11 +8196,19 @@ float* drflac_open_and_decode_f32(drflac_read_proc onRead, drflac_seek_proc onSe #ifndef DR_FLAC_NO_STDIO drflac_int32* drflac_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount) { - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalPCMFrameCount) *totalPCMFrameCount = 0; + drflac* pFlac; - drflac* pFlac = drflac_open_file(filename); + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + + pFlac = drflac_open_file(filename); if (pFlac == NULL) { return NULL; } @@ -7688,23 +8218,35 @@ drflac_int32* drflac_open_file_and_read_pcm_frames_s32(const char* filename, uns drflac_int32* drflac_open_and_decode_file_s32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalSampleCountOut) { - // Safety. - if (channelsOut) *channelsOut = 0; - if (sampleRateOut) *sampleRateOut = 0; - if (totalSampleCountOut) *totalSampleCountOut = 0; - unsigned int channels; unsigned int sampleRate; drflac_uint64 totalPCMFrameCount; + drflac_int32* pResult; - drflac_int32* pResult = drflac_open_file_and_read_pcm_frames_s32(filename, &channels, &sampleRate, &totalPCMFrameCount); + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalSampleCountOut) { + *totalSampleCountOut = 0; + } + + pResult = drflac_open_file_and_read_pcm_frames_s32(filename, &channels, &sampleRate, &totalPCMFrameCount); if (pResult == NULL) { return NULL; } - if (channelsOut) *channelsOut = channels; - if (sampleRateOut) *sampleRateOut = sampleRate; - if (totalSampleCountOut) *totalSampleCountOut = totalPCMFrameCount * channels; + if (channelsOut) { + *channelsOut = channels; + } + if (sampleRateOut) { + *sampleRateOut = sampleRate; + } + if (totalSampleCountOut) { + *totalSampleCountOut = totalPCMFrameCount * channels; + } return pResult; } @@ -7712,11 +8254,19 @@ drflac_int32* drflac_open_and_decode_file_s32(const char* filename, unsigned int drflac_int16* drflac_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount) { - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalPCMFrameCount) *totalPCMFrameCount = 0; + drflac* pFlac; - drflac* pFlac = drflac_open_file(filename); + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + + pFlac = drflac_open_file(filename); if (pFlac == NULL) { return NULL; } @@ -7726,23 +8276,35 @@ drflac_int16* drflac_open_file_and_read_pcm_frames_s16(const char* filename, uns drflac_int16* drflac_open_and_decode_file_s16(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalSampleCountOut) { - // Safety. - if (channelsOut) *channelsOut = 0; - if (sampleRateOut) *sampleRateOut = 0; - if (totalSampleCountOut) *totalSampleCountOut = 0; - unsigned int channels; unsigned int sampleRate; drflac_uint64 totalPCMFrameCount; + drflac_int16* pResult; - drflac_int16* pResult = drflac_open_file_and_read_pcm_frames_s16(filename, &channels, &sampleRate, &totalPCMFrameCount); + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalSampleCountOut) { + *totalSampleCountOut = 0; + } + + pResult = drflac_open_file_and_read_pcm_frames_s16(filename, &channels, &sampleRate, &totalPCMFrameCount); if (pResult == NULL) { return NULL; } - if (channelsOut) *channelsOut = channels; - if (sampleRateOut) *sampleRateOut = sampleRate; - if (totalSampleCountOut) *totalSampleCountOut = totalPCMFrameCount * channels; + if (channelsOut) { + *channelsOut = channels; + } + if (sampleRateOut) { + *sampleRateOut = sampleRate; + } + if (totalSampleCountOut) { + *totalSampleCountOut = totalPCMFrameCount * channels; + } return pResult; } @@ -7750,11 +8312,19 @@ drflac_int16* drflac_open_and_decode_file_s16(const char* filename, unsigned int float* drflac_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount) { - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalPCMFrameCount) *totalPCMFrameCount = 0; + drflac* pFlac; - drflac* pFlac = drflac_open_file(filename); + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + + pFlac = drflac_open_file(filename); if (pFlac == NULL) { return NULL; } @@ -7764,23 +8334,35 @@ float* drflac_open_file_and_read_pcm_frames_f32(const char* filename, unsigned i float* drflac_open_and_decode_file_f32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalSampleCountOut) { - // Safety. - if (channelsOut) *channelsOut = 0; - if (sampleRateOut) *sampleRateOut = 0; - if (totalSampleCountOut) *totalSampleCountOut = 0; - unsigned int channels; unsigned int sampleRate; drflac_uint64 totalPCMFrameCount; + float* pResult; - float* pResult = drflac_open_file_and_read_pcm_frames_f32(filename, &channels, &sampleRate, &totalPCMFrameCount); + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalSampleCountOut) { + *totalSampleCountOut = 0; + } + + pResult = drflac_open_file_and_read_pcm_frames_f32(filename, &channels, &sampleRate, &totalPCMFrameCount); if (pResult == NULL) { return NULL; } - if (channelsOut) *channelsOut = channels; - if (sampleRateOut) *sampleRateOut = sampleRate; - if (totalSampleCountOut) *totalSampleCountOut = totalPCMFrameCount * channels; + if (channelsOut) { + *channelsOut = channels; + } + if (sampleRateOut) { + *sampleRateOut = sampleRate; + } + if (totalSampleCountOut) { + *totalSampleCountOut = totalPCMFrameCount * channels; + } return pResult; } @@ -7788,11 +8370,19 @@ float* drflac_open_and_decode_file_f32(const char* filename, unsigned int* chann 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) { - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalPCMFrameCount) *totalPCMFrameCount = 0; + drflac* pFlac; - drflac* pFlac = drflac_open_memory(data, dataSize); + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + + pFlac = drflac_open_memory(data, dataSize); if (pFlac == NULL) { return NULL; } @@ -7802,23 +8392,35 @@ drflac_int32* drflac_open_memory_and_read_pcm_frames_s32(const void* data, size_ drflac_int32* drflac_open_and_decode_memory_s32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalSampleCountOut) { - // Safety. - if (channelsOut) *channelsOut = 0; - if (sampleRateOut) *sampleRateOut = 0; - if (totalSampleCountOut) *totalSampleCountOut = 0; - unsigned int channels; unsigned int sampleRate; drflac_uint64 totalPCMFrameCount; + drflac_int32* pResult; - drflac_int32* pResult = drflac_open_memory_and_read_pcm_frames_s32(data, dataSize, &channels, &sampleRate, &totalPCMFrameCount); + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalSampleCountOut) { + *totalSampleCountOut = 0; + } + + pResult = drflac_open_memory_and_read_pcm_frames_s32(data, dataSize, &channels, &sampleRate, &totalPCMFrameCount); if (pResult == NULL) { return NULL; } - if (channelsOut) *channelsOut = channels; - if (sampleRateOut) *sampleRateOut = sampleRate; - if (totalSampleCountOut) *totalSampleCountOut = totalPCMFrameCount * channels; + if (channelsOut) { + *channelsOut = channels; + } + if (sampleRateOut) { + *sampleRateOut = sampleRate; + } + if (totalSampleCountOut) { + *totalSampleCountOut = totalPCMFrameCount * channels; + } return pResult; } @@ -7826,11 +8428,19 @@ drflac_int32* drflac_open_and_decode_memory_s32(const void* data, size_t dataSiz 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) { - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalPCMFrameCount) *totalPCMFrameCount = 0; + drflac* pFlac; - drflac* pFlac = drflac_open_memory(data, dataSize); + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + + pFlac = drflac_open_memory(data, dataSize); if (pFlac == NULL) { return NULL; } @@ -7840,23 +8450,35 @@ drflac_int16* drflac_open_memory_and_read_pcm_frames_s16(const void* data, size_ drflac_int16* drflac_open_and_decode_memory_s16(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalSampleCountOut) { - // Safety. - if (channelsOut) *channelsOut = 0; - if (sampleRateOut) *sampleRateOut = 0; - if (totalSampleCountOut) *totalSampleCountOut = 0; - unsigned int channels; unsigned int sampleRate; drflac_uint64 totalPCMFrameCount; + drflac_int16* pResult; - drflac_int16* pResult = drflac_open_memory_and_read_pcm_frames_s16(data, dataSize, &channels, &sampleRate, &totalPCMFrameCount); + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalSampleCountOut) { + *totalSampleCountOut = 0; + } + + pResult = drflac_open_memory_and_read_pcm_frames_s16(data, dataSize, &channels, &sampleRate, &totalPCMFrameCount); if (pResult == NULL) { return NULL; } - if (channelsOut) *channelsOut = channels; - if (sampleRateOut) *sampleRateOut = sampleRate; - if (totalSampleCountOut) *totalSampleCountOut = totalPCMFrameCount * channels; + if (channelsOut) { + *channelsOut = channels; + } + if (sampleRateOut) { + *sampleRateOut = sampleRate; + } + if (totalSampleCountOut) { + *totalSampleCountOut = totalPCMFrameCount * channels; + } return pResult; } @@ -7864,11 +8486,19 @@ drflac_int16* drflac_open_and_decode_memory_s16(const void* data, size_t dataSiz float* drflac_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount) { - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalPCMFrameCount) *totalPCMFrameCount = 0; + drflac* pFlac; - drflac* pFlac = drflac_open_memory(data, dataSize); + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + + pFlac = drflac_open_memory(data, dataSize); if (pFlac == NULL) { return NULL; } @@ -7878,23 +8508,35 @@ float* drflac_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataS float* drflac_open_and_decode_memory_f32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalSampleCountOut) { - // Safety. - if (channelsOut) *channelsOut = 0; - if (sampleRateOut) *sampleRateOut = 0; - if (totalSampleCountOut) *totalSampleCountOut = 0; - unsigned int channels; unsigned int sampleRate; drflac_uint64 totalPCMFrameCount; + float* pResult; - float* pResult = drflac_open_memory_and_read_pcm_frames_f32(data, dataSize, &channels, &sampleRate, &totalPCMFrameCount); + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalSampleCountOut) { + *totalSampleCountOut = 0; + } + + pResult = drflac_open_memory_and_read_pcm_frames_f32(data, dataSize, &channels, &sampleRate, &totalPCMFrameCount); if (pResult == NULL) { return NULL; } - if (channelsOut) *channelsOut = channels; - if (sampleRateOut) *sampleRateOut = sampleRate; - if (totalSampleCountOut) *totalSampleCountOut = totalPCMFrameCount * channels; + if (channelsOut) { + *channelsOut = channels; + } + if (sampleRateOut) { + *sampleRateOut = sampleRate; + } + if (totalSampleCountOut) { + *totalSampleCountOut = totalPCMFrameCount * channels; + } return pResult; } @@ -7920,21 +8562,29 @@ void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut) { - // Safety. - if (pCommentLengthOut) *pCommentLengthOut = 0; + drflac_int32 length; + const char* pComment; + + /* Safety. */ + if (pCommentLengthOut) { + *pCommentLengthOut = 0; + } if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) { return NULL; } - drflac_uint32 length = drflac__le2host_32(*(const drflac_uint32*)pIter->pRunningData); + length = drflac__le2host_32(*(const drflac_uint32*)pIter->pRunningData); pIter->pRunningData += 4; - const char* pComment = pIter->pRunningData; + pComment = pIter->pRunningData; pIter->pRunningData += length; pIter->countRemaining -= 1; - if (pCommentLengthOut) *pCommentLengthOut = length; + if (pCommentLengthOut) { + *pCommentLengthOut = length; + } + return pComment; } @@ -7953,16 +8603,19 @@ void drflac_init_cuesheet_track_iterator(drflac_cuesheet_track_iterator* pIter, drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter, drflac_cuesheet_track* pCuesheetTrack) { + drflac_cuesheet_track cuesheetTrack; + const char* pRunningData; + drflac_uint64 offsetHi; + drflac_uint64 offsetLo; + if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) { return DRFLAC_FALSE; } - drflac_cuesheet_track cuesheetTrack; + pRunningData = pIter->pRunningData; - const char* pRunningData = pIter->pRunningData; - - drflac_uint64 offsetHi = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; - drflac_uint64 offsetLo = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + offsetHi = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + offsetLo = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; cuesheetTrack.offset = offsetLo | (offsetHi << 32); cuesheetTrack.trackNumber = pRunningData[0]; pRunningData += 1; drflac_copy_memory(cuesheetTrack.ISRC, pRunningData, sizeof(cuesheetTrack.ISRC)); pRunningData += 12; @@ -7974,235 +8627,267 @@ drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter, pIter->pRunningData = pRunningData; pIter->countRemaining -= 1; - if (pCuesheetTrack) *pCuesheetTrack = cuesheetTrack; + if (pCuesheetTrack) { + *pCuesheetTrack = cuesheetTrack; + } + return DRFLAC_TRUE; } #if defined(__GNUC__) #pragma GCC diagnostic pop #endif -#endif //DR_FLAC_IMPLEMENTATION - - -// REVISION HISTORY -// -// v0.11.5 - 2018-04-19 -// - Fix a compiler error with GCC. -// -// v0.11.4 - 2018-04-17 -// - Fix some warnings with GCC when compiling with -std=c99. -// -// v0.11.3 - 2018-04-07 -// - Silence warnings with GCC. -// -// v0.11.2 - 2018-03-10 -// - Fix a warning. -// -// v0.11.1 - 2018-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*/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. -// -// v0.2a - 2016-05-10 -// - Made drflac_open_and_decode() more robust. -// - Removed an unused debugging variable -// -// v0.2 - 2016-05-09 -// - Added support for Ogg encapsulation. -// - API CHANGE. Have the onSeek callback take a third argument which specifies whether or not the seek -// should be relative to the start or the current position. Also changes the seeking rules such that -// seeking offsets will never be negative. -// - Have drflac_open_and_decode() fail gracefully if the stream has an unknown total sample count. -// -// v0.1b - 2016-05-07 -// - Properly close the file handle in drflac_open_file() and family when the decoder fails to initialize. -// - Removed a stale comment. -// -// v0.1a - 2016-05-05 -// - Minor formatting changes. -// - Fixed a warning on the GCC build. -// -// v0.1 - 2016-05-03 -// - Initial versioned release. +#endif /* DR_FLAC_IMPLEMENTATION */ /* +REVISION HISTORY +================ +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. + +v0.2a - 2016-05-10 + - Made drflac_open_and_decode() more robust. + - Removed an unused debugging variable + +v0.2 - 2016-05-09 + - Added support for Ogg encapsulation. + - API CHANGE. Have the onSeek callback take a third argument which specifies whether or not the seek + should be relative to the start or the current position. Also changes the seeking rules such that + seeking offsets will never be negative. + - Have drflac_open_and_decode() fail gracefully if the stream has an unknown total sample count. + +v0.1b - 2016-05-07 + - Properly close the file handle in drflac_open_file() and family when the decoder fails to initialize. + - Removed a stale comment. + +v0.1a - 2016-05-05 + - Minor formatting changes. + - Fixed a warning on the GCC build. + +v0.1 - 2016-05-03 + - Initial versioned release. +*/ + +/* +This software is available as a choice of the following licenses. Choose +whichever you prefer. + +=============================================================================== +ALTERNATIVE 1 - Public Domain (www.unlicense.org) +=============================================================================== This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to + +=============================================================================== +ALTERNATIVE 2 - MIT No Attribution +=============================================================================== +Copyright 2018 David Reid + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. */ diff --git a/extras/dr_mp3.h b/extras/dr_mp3.h index 465438bf..52a602b6 100644 --- a/extras/dr_mp3.h +++ b/extras/dr_mp3.h @@ -1,57 +1,61 @@ -// MP3 audio decoder. Public domain. See "unlicense" statement at the end of this file. -// dr_mp3 - v0.4.1 - 2018-12-30 -// -// David Reid - mackron@gmail.com -// -// Based off minimp3 (https://github.com/lieff/minimp3) which is where the real work was done. See the bottom of this file for -// differences between minimp3 and dr_mp3. +/* +MP3 audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file. +dr_mp3 - v0.4.3 - 2019-05-05 -// USAGE -// ===== -// dr_mp3 is a single-file library. To use it, do something like the following in one .c file. -// #define DR_MP3_IMPLEMENTATION -// #include "dr_mp3.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: -// -// drmp3 mp3; -// if (!drmp3_init_file(&mp3, "MySong.mp3", NULL)) { -// // Failed to open file -// } -// -// ... -// -// drmp3_uint64 framesRead = drmp3_read_pcm_frames_f32(pMP3, framesToRead, pFrames); -// -// The drmp3 object is transparent so you can get access to the channel count and sample rate like so: -// -// drmp3_uint32 channels = mp3.channels; -// drmp3_uint32 sampleRate = mp3.sampleRate; -// -// The third parameter of drmp3_init_file() in the example above allows you to control the output channel count and sample rate. It -// is a pointer to a drmp3_config object. Setting any of the variables of this object to 0 will cause dr_mp3 to use defaults. -// -// The example above initializes a decoder from a file, but you can also initialize it from a block of memory and read and seek -// callbacks with drmp3_init_memory() and drmp3_init() respectively. -// -// You do not need to do any annoying memory management when reading PCM frames - this is all managed internally. You can request -// any number of PCM frames in each call to drmp3_read_pcm_frames_f32() and it will return as many PCM frames as it can, up to the -// requested amount. -// -// You can also decode an entire file in one go with drmp3_open_and_read_f32(), drmp3_open_memory_and_read_f32() and -// drmp3_open_file_and_read_f32(). -// -// -// OPTIONS -// ======= -// #define these options before including this file. -// -// #define DR_MP3_NO_STDIO -// Disable drmp3_init_file(), etc. -// -// #define DR_MP3_NO_SIMD -// Disable SIMD optimizations. +David Reid - mackron@gmail.com + +Based off minimp3 (https://github.com/lieff/minimp3) which is where the real work was done. See the bottom of this file for +differences between minimp3 and dr_mp3. +*/ + +/* +USAGE +===== +dr_mp3 is a single-file library. To use it, do something like the following in one .c file. + #define DR_MP3_IMPLEMENTATION + #include "dr_mp3.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: + + drmp3 mp3; + if (!drmp3_init_file(&mp3, "MySong.mp3", NULL)) { + // Failed to open file + } + + ... + + drmp3_uint64 framesRead = drmp3_read_pcm_frames_f32(pMP3, framesToRead, pFrames); + +The drmp3 object is transparent so you can get access to the channel count and sample rate like so: + + drmp3_uint32 channels = mp3.channels; + drmp3_uint32 sampleRate = mp3.sampleRate; + +The third parameter of drmp3_init_file() in the example above allows you to control the output channel count and sample rate. It +is a pointer to a drmp3_config object. Setting any of the variables of this object to 0 will cause dr_mp3 to use defaults. + +The example above initializes a decoder from a file, but you can also initialize it from a block of memory and read and seek +callbacks with drmp3_init_memory() and drmp3_init() respectively. + +You do not need to do any annoying memory management when reading PCM frames - this is all managed internally. You can request +any number of PCM frames in each call to drmp3_read_pcm_frames_f32() and it will return as many PCM frames as it can, up to the +requested amount. + +You can also decode an entire file in one go with drmp3_open_and_read_f32(), drmp3_open_memory_and_read_f32() and +drmp3_open_file_and_read_f32(). + + +OPTIONS +======= +#define these options before including this file. + +#define DR_MP3_NO_STDIO + Disable drmp3_init_file(), etc. + +#define DR_MP3_NO_SIMD + Disable SIMD optimizations. +*/ #ifndef dr_mp3_h #define dr_mp3_h @@ -90,9 +94,20 @@ typedef drmp3_uint32 drmp3_bool32; #define DRMP3_MAX_PCM_FRAMES_PER_MP3_FRAME 1152 #define DRMP3_MAX_SAMPLES_PER_FRAME (DRMP3_MAX_PCM_FRAMES_PER_MP3_FRAME*2) +#ifdef _MSC_VER +#define DRMP3_INLINE __forceinline +#else +#ifdef __GNUC__ +#define DRMP3_INLINE __inline__ __attribute__((always_inline)) +#else +#define DRMP3_INLINE +#endif +#endif -// Low Level Push API -// ================== +/* +Low Level Push API +================== +*/ typedef struct { int frame_bytes, channels, hz, layer, bitrate_kbps; @@ -105,23 +120,30 @@ typedef struct unsigned char header[4], reserv_buf[511]; } drmp3dec; -// Initializes a low level decoder. +/* Initializes a low level decoder. */ void drmp3dec_init(drmp3dec *dec); -// Reads a frame from a low level decoder. +/* Reads a frame from a low level decoder. */ int drmp3dec_decode_frame(drmp3dec *dec, const unsigned char *mp3, int mp3_bytes, void *pcm, drmp3dec_frame_info *info); -// Helper for converting between f32 and s16. +/* Helper for converting between f32 and s16. */ void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, int num_samples); - -// Main API (Pull API) -// =================== +/* +Main API (Pull API) +=================== +*/ +#ifndef DR_MP3_DEFAULT_CHANNELS +#define DR_MP3_DEFAULT_CHANNELS 2 +#endif +#ifndef DR_MP3_DEFAULT_SAMPLE_RATE +#define DR_MP3_DEFAULT_SAMPLE_RATE 44100 +#endif typedef struct drmp3_src drmp3_src; -typedef drmp3_uint64 (* drmp3_src_read_proc)(drmp3_src* pSRC, drmp3_uint64 frameCount, void* pFramesOut, void* pUserData); // Returns the number of frames that were read. +typedef drmp3_uint64 (* drmp3_src_read_proc)(drmp3_src* pSRC, drmp3_uint64 frameCount, void* pFramesOut, void* pUserData); /* Returns the number of frames that were read. */ typedef enum { @@ -144,7 +166,7 @@ typedef struct drmp3_uint32 sampleRateOut; drmp3_uint32 channels; drmp3_src_algorithm algorithm; - drmp3_uint32 cacheSizeInFrames; // The number of frames to read from the client at a time. + drmp3_uint32 cacheSizeInFrames; /* The number of frames to read from the client at a time. */ } drmp3_src_config; struct drmp3_src @@ -153,7 +175,7 @@ struct drmp3_src drmp3_src_read_proc onRead; void* pUserData; float bin[256]; - drmp3_src_cache cache; // <-- For simplifying and optimizing client -> memory reading. + drmp3_src_cache cache; /* <-- For simplifying and optimizing client -> memory reading. */ union { struct @@ -173,34 +195,38 @@ typedef enum typedef struct { - drmp3_uint64 seekPosInBytes; // Points to the first byte of an MP3 frame. - drmp3_uint64 pcmFrameIndex; // The index of the PCM frame this seek point targets. - drmp3_uint16 mp3FramesToDiscard; // The number of whole MP3 frames to be discarded before pcmFramesToDiscard. - drmp3_uint16 pcmFramesToDiscard; // The number of leading samples to read and discard. These are discarded after mp3FramesToDiscard. + drmp3_uint64 seekPosInBytes; /* Points to the first byte of an MP3 frame. */ + drmp3_uint64 pcmFrameIndex; /* The index of the PCM frame this seek point targets. */ + drmp3_uint16 mp3FramesToDiscard; /* The number of whole MP3 frames to be discarded before pcmFramesToDiscard. */ + drmp3_uint16 pcmFramesToDiscard; /* The number of leading samples to read and discard. These are discarded after mp3FramesToDiscard. */ } drmp3_seek_point; -// Callback for when data is read. Return value is the number of bytes actually read. -// -// pUserData [in] The user data that was passed to drmp3_init(), drmp3_open() and family. -// pBufferOut [out] The output buffer. -// bytesToRead [in] The number of bytes to read. -// -// Returns the number of bytes actually read. -// -// 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. +/* +Callback for when data is read. Return value is the number of bytes actually read. + +pUserData [in] The user data that was passed to drmp3_init(), drmp3_open() and family. +pBufferOut [out] The output buffer. +bytesToRead [in] The number of bytes to read. + +Returns the number of bytes actually read. + +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 (* drmp3_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); -// Callback for when data needs to be seeked. -// -// pUserData [in] The user data that was passed to drmp3_init(), drmp3_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. -// -// Returns whether or not the seek was successful. -// -// Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which -// will be either drmp3_seek_origin_start or drmp3_seek_origin_current. +/* +Callback for when data needs to be seeked. + +pUserData [in] The user data that was passed to drmp3_init(), drmp3_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. + +Returns whether or not the seek was successful. + +Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which +will be either drmp3_seek_origin_start or drmp3_seek_origin_current. +*/ typedef drmp3_bool32 (* drmp3_seek_proc)(void* pUserData, int offset, drmp3_seek_origin origin); typedef struct @@ -218,16 +244,16 @@ typedef struct drmp3_read_proc onRead; drmp3_seek_proc onSeek; void* pUserData; - drmp3_uint32 mp3FrameChannels; // The number of channels in the currently loaded MP3 frame. Internal use only. - drmp3_uint32 mp3FrameSampleRate; // The sample rate of the currently loaded MP3 frame. Internal use only. + drmp3_uint32 mp3FrameChannels; /* The number of channels in the currently loaded MP3 frame. Internal use only. */ + drmp3_uint32 mp3FrameSampleRate; /* The sample rate of the currently loaded MP3 frame. Internal use only. */ drmp3_uint32 pcmFramesConsumedInMP3Frame; drmp3_uint32 pcmFramesRemainingInMP3Frame; - drmp3_uint8 pcmFrames[sizeof(float)*DRMP3_MAX_SAMPLES_PER_FRAME]; // <-- Multipled by sizeof(float) to ensure there's enough room for DR_MP3_FLOAT_OUTPUT. - drmp3_uint64 currentPCMFrame; // The current PCM frame, globally, based on the output sample rate. Mainly used for seeking. - drmp3_uint64 streamCursor; // The current byte the decoder is sitting on in the raw stream. + drmp3_uint8 pcmFrames[sizeof(float)*DRMP3_MAX_SAMPLES_PER_FRAME]; /* <-- Multipled by sizeof(float) to ensure there's enough room for DR_MP3_FLOAT_OUTPUT. */ + drmp3_uint64 currentPCMFrame; /* The current PCM frame, globally, based on the output sample rate. Mainly used for seeking. */ + drmp3_uint64 streamCursor; /* The current byte the decoder is sitting on in the raw stream. */ drmp3_src src; - drmp3_seek_point* pSeekPoints; // NULL by default. Set with drmp3_bind_seek_table(). Memory is owned by the client. dr_mp3 will never attempt to free this pointer. - drmp3_uint32 seekPointCount; // The number of items in pSeekPoints. When set to 0 assumes to no seek table. Defaults to zero. + drmp3_seek_point* pSeekPoints; /* NULL by default. Set with drmp3_bind_seek_table(). Memory is owned by the client. dr_mp3 will never attempt to free this pointer. */ + drmp3_uint32 seekPointCount; /* The number of items in pSeekPoints. When set to 0 assumes to no seek table. Defaults to zero. */ size_t dataSize; size_t dataCapacity; drmp3_uint8* pData; @@ -237,111 +263,156 @@ typedef struct const drmp3_uint8* pData; size_t dataSize; size_t currentReadPos; - } memory; // Only used for decoders that were opened against a block of memory. + } memory; /* Only used for decoders that were opened against a block of memory. */ } drmp3; -// Initializes an MP3 decoder. -// -// 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. -// -// Returns true if successful; false otherwise. -// -// Close the loader with drmp3_uninit(). -// -// See also: drmp3_init_file(), drmp3_init_memory(), drmp3_uninit() +/* +Initializes an MP3 decoder. + +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. + +Returns true if successful; false otherwise. + +Close the loader with drmp3_uninit(). + +See also: drmp3_init_file(), drmp3_init_memory(), drmp3_uninit() +*/ drmp3_bool32 drmp3_init(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, const drmp3_config* pConfig); -// Initializes an MP3 decoder from a block of memory. -// -// This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for -// the lifetime of the drmp3 object. -// -// The buffer should contain the contents of the entire MP3 file. +/* +Initializes an MP3 decoder from a block of memory. + +This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for +the lifetime of the drmp3 object. + +The buffer should contain the contents of the entire MP3 file. +*/ drmp3_bool32 drmp3_init_memory(drmp3* pMP3, const void* pData, size_t dataSize, const drmp3_config* pConfig); #ifndef DR_MP3_NO_STDIO -// Initializes an MP3 decoder from a file. -// -// This holds the internal FILE object until drmp3_uninit() is called. Keep this in mind if you're caching drmp3 -// objects because the operating system may restrict the number of file handles an application can have open at -// any given time. +/* +Initializes an MP3 decoder from a file. + +This holds the internal FILE object until drmp3_uninit() is called. Keep this in mind if you're caching drmp3 +objects because the operating system may restrict the number of file handles an application can have open at +any given time. +*/ drmp3_bool32 drmp3_init_file(drmp3* pMP3, const char* filePath, const drmp3_config* pConfig); #endif -// Uninitializes an MP3 decoder. +/* +Uninitializes an MP3 decoder. +*/ void drmp3_uninit(drmp3* pMP3); -// Reads PCM frames as interleaved 32-bit IEEE floating point PCM. -// -// Note that framesToRead specifies the number of PCM frames to read, _not_ the number of MP3 frames. +/* +Reads PCM frames as interleaved 32-bit IEEE floating point PCM. + +Note that framesToRead specifies the number of PCM frames to read, _not_ the number of MP3 frames. +*/ drmp3_uint64 drmp3_read_pcm_frames_f32(drmp3* pMP3, drmp3_uint64 framesToRead, float* pBufferOut); -// Seeks to a specific frame. -// -// Note that this is _not_ an MP3 frame, but rather a PCM frame. +/* +Reads PCM frames as interleaved signed 16-bit integer PCM. + +Note that framesToRead specifies the number of PCM frames to read, _not_ the number of MP3 frames. +*/ +drmp3_uint64 drmp3_read_pcm_frames_s16(drmp3* pMP3, drmp3_uint64 framesToRead, drmp3_int16* pBufferOut); + +/* +Seeks to a specific frame. + +Note that this is _not_ an MP3 frame, but rather a PCM frame. +*/ drmp3_bool32 drmp3_seek_to_pcm_frame(drmp3* pMP3, drmp3_uint64 frameIndex); -// Calculates the total number of PCM frames in the MP3 stream. Cannot be used for infinite streams such as internet -// radio. Runs in linear time. Returns 0 on error. +/* +Calculates the total number of PCM frames in the MP3 stream. Cannot be used for infinite streams such as internet +radio. Runs in linear time. Returns 0 on error. +*/ drmp3_uint64 drmp3_get_pcm_frame_count(drmp3* pMP3); -// Calculates the total number of MP3 frames in the MP3 stream. Cannot be used for infinite streams such as internet -// radio. Runs in linear time. Returns 0 on error. +/* +Calculates the total number of MP3 frames in the MP3 stream. Cannot be used for infinite streams such as internet +radio. Runs in linear time. Returns 0 on error. +*/ drmp3_uint64 drmp3_get_mp3_frame_count(drmp3* pMP3); -// Calculates the seekpoints based on PCM frames. This is slow. -// -// pSeekpoint count is a pointer to a uint32 containing the seekpoint count. On input it contains the desired count. -// On output it contains the actual count. The reason for this design is that the client may request too many -// seekpoints, in which case dr_mp3 will return a corrected count. -// -// Note that seektable seeking is not quite sample exact when the MP3 stream contains inconsistent sample rates. +/* +Calculates the total number of MP3 and PCM frames in the MP3 stream. Cannot be used for infinite streams such as internet +radio. Runs in linear time. Returns 0 on error. + +This is equivalent to calling drmp3_get_mp3_frame_count() and drmp3_get_pcm_frame_count() except that it's more efficient. +*/ +drmp3_bool32 drmp3_get_mp3_and_pcm_frame_count(drmp3* pMP3, drmp3_uint64* pMP3FrameCount, drmp3_uint64* pPCMFrameCount); + +/* +Calculates the seekpoints based on PCM frames. This is slow. + +pSeekpoint count is a pointer to a uint32 containing the seekpoint count. On input it contains the desired count. +On output it contains the actual count. The reason for this design is that the client may request too many +seekpoints, in which case dr_mp3 will return a corrected count. + +Note that seektable seeking is not quite sample exact when the MP3 stream contains inconsistent sample rates. +*/ drmp3_bool32 drmp3_calculate_seek_points(drmp3* pMP3, drmp3_uint32* pSeekPointCount, drmp3_seek_point* pSeekPoints); -// Binds a seek table to the decoder. -// -// This does _not_ make a copy of pSeekPoints - it only references it. It is up to the application to ensure this -// remains valid while it is bound to the decoder. -// -// Use drmp3_calculate_seek_points() to calculate the seek points. +/* +Binds a seek table to the decoder. + +This does _not_ make a copy of pSeekPoints - it only references it. It is up to the application to ensure this +remains valid while it is bound to the decoder. + +Use drmp3_calculate_seek_points() to calculate the seek points. +*/ drmp3_bool32 drmp3_bind_seek_table(drmp3* pMP3, drmp3_uint32 seekPointCount, drmp3_seek_point* pSeekPoints); +/* +Opens an decodes an entire MP3 stream as a single operation. -// Opens an decodes an entire MP3 stream as a single operation. -// -// pConfig is both an input and output. On input it contains what you want. On output it contains what you got. -// -// Free the returned pointer with drmp3_free(). +pConfig is both an input and output. On input it contains what you want. On output it contains what you got. + +Free the returned pointer with drmp3_free(). +*/ float* drmp3_open_and_read_f32(drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount); +drmp3_int16* drmp3_open_and_read_s16(drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount); + float* drmp3_open_memory_and_read_f32(const void* pData, size_t dataSize, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount); +drmp3_int16* drmp3_open_memory_and_read_s16(const void* pData, size_t dataSize, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount); + #ifndef DR_MP3_NO_STDIO float* drmp3_open_file_and_read_f32(const char* filePath, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount); +drmp3_int16* drmp3_open_file_and_read_s16(const char* filePath, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount); #endif -// Frees any memory that was allocated by a public drmp3 API. +/* +Frees any memory that was allocated by a public drmp3 API. +*/ void drmp3_free(void* p); #ifdef __cplusplus } #endif -#endif // dr_mp3_h +#endif /* dr_mp3_h */ -///////////////////////////////////////////////////// -// -// IMPLEMENTATION -// -///////////////////////////////////////////////////// +/************************************************************************************************************************************************************ + ************************************************************************************************************************************************************ + + IMPLEMENTATION + + ************************************************************************************************************************************************************ + ************************************************************************************************************************************************************/ #ifdef DR_MP3_IMPLEMENTATION #include #include #include -#include // For INT_MAX +#include /* For INT_MAX */ -// Disable SIMD when compiling with TCC for now. +/* Disable SIMD when compiling with TCC for now. */ #if defined(__TINYC__) #define DR_MP3_NO_SIMD #endif @@ -808,8 +879,8 @@ static int drmp3_L3_read_side_info(drmp3_bs *bs, drmp3_L3_gr_info *gr, const drm unsigned tables, scfsi = 0; int main_data_begin, part_23_sum = 0; - int sr_idx = DRMP3_HDR_GET_MY_SAMPLE_RATE(hdr); sr_idx -= (sr_idx != 0); int gr_count = DRMP3_HDR_IS_MONO(hdr) ? 1 : 2; + int sr_idx = DRMP3_HDR_GET_MY_SAMPLE_RATE(hdr); sr_idx -= (sr_idx != 0); if (DRMP3_HDR_TEST_MPEG1(hdr)) { @@ -1682,9 +1753,10 @@ typedef drmp3_int16 drmp3d_sample_t; static drmp3_int16 drmp3d_scale_pcm(float sample) { + drmp3_int16 s; if (sample >= 32766.5) return (drmp3_int16) 32767; if (sample <= -32767.5) return (drmp3_int16)-32768; - drmp3_int16 s = (drmp3_int16)(sample + .5f); + s = (drmp3_int16)(sample + .5f); s -= (s < 0); /* away from zero, to be compliant */ return (drmp3_int16)s; } @@ -2022,11 +2094,12 @@ int drmp3dec_decode_frame(drmp3dec *dec, const unsigned char *mp3, int mp3_bytes #ifdef DR_MP3_ONLY_MP3 return 0; #else + drmp3_L12_scale_info sci[1]; + if (pcm == NULL) { return drmp3_hdr_frame_samples(hdr); } - drmp3_L12_scale_info sci[1]; drmp3_L12_read_scale_info(hdr, bs_frame, sci); memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); @@ -2113,11 +2186,11 @@ void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, int num_samples) -/////////////////////////////////////////////////////////////////////////////// -// -// Main Public API -// -/////////////////////////////////////////////////////////////////////////////// +/************************************************************************************************************************************************************ + + Main Public API + + ************************************************************************************************************************************************************/ #if defined(SIZE_MAX) #define DRMP3_SIZE_MAX SIZE_MAX @@ -2129,19 +2202,13 @@ void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, int num_samples) #endif #endif -// Options. -#ifndef DR_MP3_DEFAULT_CHANNELS -#define DR_MP3_DEFAULT_CHANNELS 2 -#endif -#ifndef DR_MP3_DEFAULT_SAMPLE_RATE -#define DR_MP3_DEFAULT_SAMPLE_RATE 44100 -#endif +/* Options. */ #ifndef DRMP3_SEEK_LEADING_MP3_FRAMES #define DRMP3_SEEK_LEADING_MP3_FRAMES 2 #endif -// Standard library stuff. +/* Standard library stuff. */ #ifndef DRMP3_ASSERT #include #define DRMP3_ASSERT(expression) assert(expression) @@ -2174,16 +2241,17 @@ void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, int num_samples) #define drmp3_max(x, y) (((x) > (y)) ? (x) : (y)) #define drmp3_min(x, y) (((x) < (y)) ? (x) : (y)) -#define DRMP3_DATA_CHUNK_SIZE 16384 // The size in bytes of each chunk of data to read from the MP3 stream. minimp3 recommends 16K. +#define DRMP3_DATA_CHUNK_SIZE 16384 /* The size in bytes of each chunk of data to read from the MP3 stream. minimp3 recommends 16K. */ -static inline float drmp3_mix_f32(float x, float y, float a) +static DRMP3_INLINE float drmp3_mix_f32(float x, float y, float a) { return x*(1-a) + y*a; } static void drmp3_blend_f32(float* pOut, float* pInA, float* pInB, float factor, drmp3_uint32 channels) { - for (drmp3_uint32 i = 0; i < channels; ++i) { + drmp3_uint32 i; + for (i = 0; i < channels; ++i) { pOut[i] = drmp3_mix_f32(pInA[i], pInB[i], factor); } } @@ -2200,17 +2268,20 @@ void drmp3_src_cache_init(drmp3_src* pSRC, drmp3_src_cache* pCache) drmp3_uint64 drmp3_src_cache_read_frames(drmp3_src_cache* pCache, drmp3_uint64 frameCount, float* pFramesOut) { + drmp3_uint32 channels; + drmp3_uint64 totalFramesRead = 0; + drmp3_assert(pCache != NULL); drmp3_assert(pCache->pSRC != NULL); drmp3_assert(pCache->pSRC->onRead != NULL); drmp3_assert(frameCount > 0); drmp3_assert(pFramesOut != NULL); - drmp3_uint32 channels = pCache->pSRC->config.channels; + channels = pCache->pSRC->config.channels; - drmp3_uint64 totalFramesRead = 0; while (frameCount > 0) { - // If there's anything in memory go ahead and copy that over first. + /* If there's anything in memory go ahead and copy that over first. */ + drmp3_uint32 framesToReadFromClient; drmp3_uint64 framesRemainingInMemory = pCache->cachedFrameCount - pCache->iNextFrame; drmp3_uint64 framesToReadFromMemory = frameCount; if (framesToReadFromMemory > framesRemainingInMemory) { @@ -2227,14 +2298,14 @@ drmp3_uint64 drmp3_src_cache_read_frames(drmp3_src_cache* pCache, drmp3_uint64 f } - // At this point there are still more frames to read from the client, so we'll need to reload the cache with fresh data. + /* At this point there are still more frames to read from the client, so we'll need to reload the cache with fresh data. */ drmp3_assert(frameCount > 0); pFramesOut += framesToReadFromMemory * channels; pCache->iNextFrame = 0; pCache->cachedFrameCount = 0; - drmp3_uint32 framesToReadFromClient = drmp3_countof(pCache->pCachedFrames) / pCache->pSRC->config.channels; + framesToReadFromClient = drmp3_countof(pCache->pCachedFrames) / pCache->pSRC->config.channels; if (framesToReadFromClient > pCache->pSRC->config.cacheSizeInFrames) { framesToReadFromClient = pCache->pSRC->config.cacheSizeInFrames; } @@ -2242,7 +2313,7 @@ drmp3_uint64 drmp3_src_cache_read_frames(drmp3_src_cache* pCache, drmp3_uint64 f pCache->cachedFrameCount = (drmp3_uint32)pCache->pSRC->onRead(pCache->pSRC, framesToReadFromClient, pCache->pCachedFrames, pCache->pSRC->pUserData); - // Get out of this loop if nothing was able to be retrieved. + /* Get out of this loop if nothing was able to be retrieved. */ if (pCache->cachedFrameCount == 0) { break; } @@ -2257,11 +2328,19 @@ drmp3_uint64 drmp3_src_read_frames_linear(drmp3_src* pSRC, drmp3_uint64 frameCou drmp3_bool32 drmp3_src_init(const drmp3_src_config* pConfig, drmp3_src_read_proc onRead, void* pUserData, drmp3_src* pSRC) { - if (pSRC == NULL) return DRMP3_FALSE; + if (pSRC == NULL) { + return DRMP3_FALSE; + } + drmp3_zero_object(pSRC); - if (pConfig == NULL || onRead == NULL) return DRMP3_FALSE; - if (pConfig->channels == 0 || pConfig->channels > 2) return DRMP3_FALSE; + if (pConfig == NULL || onRead == NULL) { + return DRMP3_FALSE; + } + + if (pConfig->channels == 0 || pConfig->channels > 2) { + return DRMP3_FALSE; + } pSRC->config = *pConfig; pSRC->onRead = onRead; @@ -2277,9 +2356,11 @@ drmp3_bool32 drmp3_src_init(const drmp3_src_config* pConfig, drmp3_src_read_proc drmp3_bool32 drmp3_src_set_input_sample_rate(drmp3_src* pSRC, drmp3_uint32 sampleRateIn) { - if (pSRC == NULL) return DRMP3_FALSE; + if (pSRC == NULL) { + return DRMP3_FALSE; + } - // Must have a sample rate of > 0. + /* Must have a sample rate of > 0. */ if (sampleRateIn == 0) { return DRMP3_FALSE; } @@ -2290,9 +2371,11 @@ drmp3_bool32 drmp3_src_set_input_sample_rate(drmp3_src* pSRC, drmp3_uint32 sampl drmp3_bool32 drmp3_src_set_output_sample_rate(drmp3_src* pSRC, drmp3_uint32 sampleRateOut) { - if (pSRC == NULL) return DRMP3_FALSE; + if (pSRC == NULL) { + return DRMP3_FALSE; + } - // Must have a sample rate of > 0. + /* Must have a sample rate of > 0. */ if (sampleRateOut == 0) { return DRMP3_FALSE; } @@ -2303,16 +2386,20 @@ drmp3_bool32 drmp3_src_set_output_sample_rate(drmp3_src* pSRC, drmp3_uint32 samp drmp3_uint64 drmp3_src_read_frames_ex(drmp3_src* pSRC, drmp3_uint64 frameCount, void* pFramesOut, drmp3_bool32 flush) { - if (pSRC == NULL || frameCount == 0 || pFramesOut == NULL) return 0; + drmp3_src_algorithm algorithm; - drmp3_src_algorithm algorithm = pSRC->config.algorithm; + if (pSRC == NULL || frameCount == 0 || pFramesOut == NULL) { + return 0; + } - // Always use passthrough if the sample rates are the same. + algorithm = pSRC->config.algorithm; + + /* Always use passthrough if the sample rates are the same. */ if (pSRC->config.sampleRateIn == pSRC->config.sampleRateOut) { algorithm = drmp3_src_algorithm_none; } - // Could just use a function pointer instead of a switch for this... + /* Could just use a function pointer instead of a switch for this... */ switch (algorithm) { case drmp3_src_algorithm_none: return drmp3_src_read_frames_passthrough(pSRC, frameCount, pFramesOut, flush); @@ -2332,19 +2419,22 @@ drmp3_uint64 drmp3_src_read_frames_passthrough(drmp3_src* pSRC, drmp3_uint64 fra drmp3_assert(frameCount > 0); drmp3_assert(pFramesOut != NULL); - (void)flush; // Passthrough need not care about flushing. + (void)flush; /* Passthrough need not care about flushing. */ return pSRC->onRead(pSRC, frameCount, pFramesOut, pSRC->pUserData); } drmp3_uint64 drmp3_src_read_frames_linear(drmp3_src* pSRC, drmp3_uint64 frameCount, void* pFramesOut, drmp3_bool32 flush) { + double factor; + drmp3_uint64 totalFramesRead; + drmp3_assert(pSRC != NULL); drmp3_assert(frameCount > 0); drmp3_assert(pFramesOut != NULL); - // For linear SRC, the bin is only 2 frames: 1 prior, 1 future. + /* For linear SRC, the bin is only 2 frames: 1 prior, 1 future. */ - // Load the bin if necessary. + /* Load the bin if necessary. */ if (!pSRC->algo.linear.isPrevFramesLoaded) { drmp3_uint64 framesRead = drmp3_src_cache_read_frames(&pSRC->cache, 1, pSRC->bin); if (framesRead == 0) { @@ -2360,11 +2450,14 @@ drmp3_uint64 drmp3_src_read_frames_linear(drmp3_src* pSRC, drmp3_uint64 frameCou pSRC->algo.linear.isNextFramesLoaded = DRMP3_TRUE; } - double factor = (double)pSRC->config.sampleRateIn / pSRC->config.sampleRateOut; + factor = (double)pSRC->config.sampleRateIn / pSRC->config.sampleRateOut; - drmp3_uint64 totalFramesRead = 0; + totalFramesRead = 0; while (frameCount > 0) { - // The bin is where the previous and next frames are located. + drmp3_uint32 i; + drmp3_uint32 framesToReadFromClient; + + /* The bin is where the previous and next frames are located. */ float* pPrevFrame = pSRC->bin; float* pNextFrame = pSRC->bin + pSRC->config.channels; @@ -2372,19 +2465,23 @@ drmp3_uint64 drmp3_src_read_frames_linear(drmp3_src* pSRC, drmp3_uint64 frameCou pSRC->algo.linear.alpha += factor; - // The new alpha value is how we determine whether or not we need to read fresh frames. - drmp3_uint32 framesToReadFromClient = (drmp3_uint32)pSRC->algo.linear.alpha; + /* The new alpha value is how we determine whether or not we need to read fresh frames. */ + framesToReadFromClient = (drmp3_uint32)pSRC->algo.linear.alpha; pSRC->algo.linear.alpha = pSRC->algo.linear.alpha - framesToReadFromClient; - for (drmp3_uint32 i = 0; i < framesToReadFromClient; ++i) { - for (drmp3_uint32 j = 0; j < pSRC->config.channels; ++j) { + for (i = 0; i < framesToReadFromClient; ++i) { + drmp3_uint64 framesRead; + drmp3_uint32 j; + + for (j = 0; j < pSRC->config.channels; ++j) { pPrevFrame[j] = pNextFrame[j]; } - drmp3_uint64 framesRead = drmp3_src_cache_read_frames(&pSRC->cache, 1, pNextFrame); + framesRead = drmp3_src_cache_read_frames(&pSRC->cache, 1, pNextFrame); if (framesRead == 0) { - for (drmp3_uint32 j = 0; j < pSRC->config.channels; ++j) { - pNextFrame[j] = 0; + drmp3_uint32 k; + for (k = 0; k < pSRC->config.channels; ++k) { + pNextFrame[k] = 0; } if (pSRC->algo.linear.isNextFramesLoaded) { @@ -2403,7 +2500,7 @@ drmp3_uint64 drmp3_src_read_frames_linear(drmp3_src* pSRC, drmp3_uint64 frameCou frameCount -= 1; totalFramesRead += 1; - // If there's no frames available we need to get out of this loop. + /* If there's no frames available we need to get out of this loop. */ if (!pSRC->algo.linear.isNextFramesLoaded && (!flush || !pSRC->algo.linear.isPrevFramesLoaded)) { break; } @@ -2444,7 +2541,7 @@ static drmp3_bool32 drmp3__on_seek_64(drmp3* pMP3, drmp3_uint64 offset, drmp3_se } - // Getting here "offset" is too large for a 32-bit integer. We just keep seeking forward until we hit the offset. + /* Getting here "offset" is too large for a 32-bit integer. We just keep seeking forward until we hit the offset. */ if (!drmp3__on_seek(pMP3, 0x7FFFFFFF, drmp3_seek_origin_start)) { return DRMP3_FALSE; } @@ -2467,152 +2564,41 @@ static drmp3_bool32 drmp3__on_seek_64(drmp3* pMP3, drmp3_uint64 offset, drmp3_se return DRMP3_TRUE; } - - - -static drmp3_uint32 drmp3_decode_next_frame_ex(drmp3* pMP3, drmp3d_sample_t* pPCMFrames, drmp3_bool32 discard) -{ - drmp3_assert(pMP3 != NULL); - drmp3_assert(pMP3->onRead != NULL); - - if (pMP3->atEnd) { - return 0; - } - - drmp3_uint32 pcmFramesRead = 0; - do { - // minimp3 recommends doing data submission in 16K chunks. If we don't have at least 16K bytes available, get more. - if (pMP3->dataSize < DRMP3_DATA_CHUNK_SIZE) { - if (pMP3->dataCapacity < DRMP3_DATA_CHUNK_SIZE) { - pMP3->dataCapacity = DRMP3_DATA_CHUNK_SIZE; - drmp3_uint8* pNewData = (drmp3_uint8*)drmp3_realloc(pMP3->pData, pMP3->dataCapacity); - if (pNewData == NULL) { - return 0; // Out of memory. - } - - pMP3->pData = pNewData; - } - - size_t bytesRead = drmp3__on_read(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); - if (bytesRead == 0) { - if (pMP3->dataSize == 0) { - pMP3->atEnd = DRMP3_TRUE; - return 0; // No data. - } - } - - pMP3->dataSize += bytesRead; - } - - if (pMP3->dataSize > INT_MAX) { - pMP3->atEnd = DRMP3_TRUE; - return 0; // File too big. - } - - drmp3dec_frame_info info; - pcmFramesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->pData, (int)pMP3->dataSize, pPCMFrames, &info); // <-- Safe size_t -> int conversion thanks to the check above. - - // Consume the data. - size_t leftoverDataSize = (pMP3->dataSize - (size_t)info.frame_bytes); - if (info.frame_bytes > 0) { - memmove(pMP3->pData, pMP3->pData + info.frame_bytes, leftoverDataSize); - pMP3->dataSize = leftoverDataSize; - } - - // pcmFramesRead will be equal to 0 if decoding failed. If it is zero and info.frame_bytes > 0 then we have successfully - // decoded the frame. A special case is if we are wanting to discard the frame, in which case we return successfully. - if (pcmFramesRead > 0 || (info.frame_bytes > 0 && discard)) { - pcmFramesRead = drmp3_hdr_frame_samples(pMP3->decoder.header); - pMP3->pcmFramesConsumedInMP3Frame = 0; - pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead; - pMP3->mp3FrameChannels = info.channels; - pMP3->mp3FrameSampleRate = info.hz; - drmp3_src_set_input_sample_rate(&pMP3->src, pMP3->mp3FrameSampleRate); - break; - } else if (info.frame_bytes == 0) { - // Need more data. minimp3 recommends doing data submission in 16K chunks. - if (pMP3->dataCapacity == pMP3->dataSize) { - // No room. Expand. - pMP3->dataCapacity += DRMP3_DATA_CHUNK_SIZE; - drmp3_uint8* pNewData = (drmp3_uint8*)drmp3_realloc(pMP3->pData, pMP3->dataCapacity); - if (pNewData == NULL) { - return 0; // Out of memory. - } - - pMP3->pData = pNewData; - } - - // Fill in a chunk. - size_t bytesRead = drmp3__on_read(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); - if (bytesRead == 0) { - pMP3->atEnd = DRMP3_TRUE; - return 0; // Error reading more data. - } - - pMP3->dataSize += bytesRead; - } - } while (DRMP3_TRUE); - - return pcmFramesRead; -} - -static drmp3_uint32 drmp3_decode_next_frame(drmp3* pMP3) -{ - drmp3_assert(pMP3 != NULL); - return drmp3_decode_next_frame_ex(pMP3, (drmp3d_sample_t*)pMP3->pcmFrames, DRMP3_FALSE); -} - -#if 0 -static drmp3_uint32 drmp3_seek_next_frame(drmp3* pMP3) -{ - drmp3_assert(pMP3 != NULL); - - drmp3_uint32 pcmFrameCount = drmp3_decode_next_frame_ex(pMP3, NULL); - if (pcmFrameCount == 0) { - return 0; - } - - // We have essentially just skipped past the frame, so just set the remaining samples to 0. - pMP3->currentPCMFrame += pcmFrameCount; - pMP3->pcmFramesConsumedInMP3Frame = pcmFrameCount; - pMP3->pcmFramesRemainingInMP3Frame = 0; - - return pcmFrameCount; -} -#endif +static drmp3_uint32 drmp3_decode_next_frame_ex(drmp3* pMP3, drmp3d_sample_t* pPCMFrames, drmp3_bool32 discard); +static drmp3_uint32 drmp3_decode_next_frame(drmp3* pMP3); static drmp3_uint64 drmp3_read_src(drmp3_src* pSRC, drmp3_uint64 frameCount, void* pFramesOut, void* pUserData) { drmp3* pMP3 = (drmp3*)pUserData; - drmp3_assert(pMP3 != NULL); - drmp3_assert(pMP3->onRead != NULL); - float* pFramesOutF = (float*)pFramesOut; drmp3_uint64 totalFramesRead = 0; + drmp3_assert(pMP3 != NULL); + drmp3_assert(pMP3->onRead != NULL); + while (frameCount > 0) { - // Read from the in-memory buffer first. + /* Read from the in-memory buffer first. */ while (pMP3->pcmFramesRemainingInMP3Frame > 0 && frameCount > 0) { drmp3d_sample_t* frames = (drmp3d_sample_t*)pMP3->pcmFrames; #ifndef DR_MP3_FLOAT_OUTPUT if (pMP3->mp3FrameChannels == 1) { if (pMP3->channels == 1) { - // Mono -> Mono. + /* Mono -> Mono. */ pFramesOutF[0] = frames[pMP3->pcmFramesConsumedInMP3Frame] / 32768.0f; } else { - // Mono -> Stereo. + /* Mono -> Stereo. */ pFramesOutF[0] = frames[pMP3->pcmFramesConsumedInMP3Frame] / 32768.0f; pFramesOutF[1] = frames[pMP3->pcmFramesConsumedInMP3Frame] / 32768.0f; } } else { if (pMP3->channels == 1) { - // Stereo -> Mono + /* Stereo -> Mono */ float sample = 0; sample += frames[(pMP3->pcmFramesConsumedInMP3Frame*pMP3->mp3FrameChannels)+0] / 32768.0f; sample += frames[(pMP3->pcmFramesConsumedInMP3Frame*pMP3->mp3FrameChannels)+1] / 32768.0f; pFramesOutF[0] = sample * 0.5f; } else { - // Stereo -> Stereo + /* Stereo -> Stereo */ pFramesOutF[0] = frames[(pMP3->pcmFramesConsumedInMP3Frame*pMP3->mp3FrameChannels)+0] / 32768.0f; pFramesOutF[1] = frames[(pMP3->pcmFramesConsumedInMP3Frame*pMP3->mp3FrameChannels)+1] / 32768.0f; } @@ -2620,22 +2606,22 @@ static drmp3_uint64 drmp3_read_src(drmp3_src* pSRC, drmp3_uint64 frameCount, voi #else if (pMP3->mp3FrameChannels == 1) { if (pMP3->channels == 1) { - // Mono -> Mono. + /* Mono -> Mono. */ pFramesOutF[0] = frames[pMP3->pcmFramesConsumedInMP3Frame]; } else { - // Mono -> Stereo. + /* Mono -> Stereo. */ pFramesOutF[0] = frames[pMP3->pcmFramesConsumedInMP3Frame]; pFramesOutF[1] = frames[pMP3->pcmFramesConsumedInMP3Frame]; } } else { if (pMP3->channels == 1) { - // Stereo -> Mono + /* Stereo -> Mono */ float sample = 0; sample += frames[(pMP3->pcmFramesConsumedInMP3Frame*pMP3->mp3FrameChannels)+0]; sample += frames[(pMP3->pcmFramesConsumedInMP3Frame*pMP3->mp3FrameChannels)+1]; pFramesOutF[0] = sample * 0.5f; } else { - // Stereo -> Stereo + /* Stereo -> Stereo */ pFramesOutF[0] = frames[(pMP3->pcmFramesConsumedInMP3Frame*pMP3->mp3FrameChannels)+0]; pFramesOutF[1] = frames[(pMP3->pcmFramesConsumedInMP3Frame*pMP3->mp3FrameChannels)+1]; } @@ -2655,8 +2641,10 @@ static drmp3_uint64 drmp3_read_src(drmp3_src* pSRC, drmp3_uint64 frameCount, voi drmp3_assert(pMP3->pcmFramesRemainingInMP3Frame == 0); - // At this point we have exhausted our in-memory buffer so we need to re-fill. Note that the sample rate may have changed - // at this point which means we'll also need to update our sample rate conversion pipeline. + /* + At this point we have exhausted our in-memory buffer so we need to re-fill. Note that the sample rate may have changed + at this point which means we'll also need to update our sample rate conversion pipeline. + */ if (drmp3_decode_next_frame(pMP3) == 0) { break; } @@ -2665,42 +2653,8 @@ static drmp3_uint64 drmp3_read_src(drmp3_src* pSRC, drmp3_uint64 frameCount, voi return totalFramesRead; } -drmp3_bool32 drmp3_init_internal(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, const drmp3_config* pConfig) +static drmp3_bool32 drmp3_init_src(drmp3* pMP3) { - drmp3_assert(pMP3 != NULL); - drmp3_assert(onRead != NULL); - - // This function assumes the output object has already been reset to 0. Do not do that here, otherwise things will break. - drmp3dec_init(&pMP3->decoder); - - // The config can be null in which case we use defaults. - drmp3_config config; - if (pConfig != NULL) { - config = *pConfig; - } else { - drmp3_zero_object(&config); - } - - pMP3->channels = config.outputChannels; - if (pMP3->channels == 0) { - pMP3->channels = DR_MP3_DEFAULT_CHANNELS; - } - - // Cannot have more than 2 channels. - if (pMP3->channels > 2) { - pMP3->channels = 2; - } - - pMP3->sampleRate = config.outputSampleRate; - if (pMP3->sampleRate == 0) { - pMP3->sampleRate = DR_MP3_DEFAULT_SAMPLE_RATE; - } - - pMP3->onRead = onRead; - pMP3->onSeek = onSeek; - pMP3->pUserData = pUserData; - - // We need a sample rate converter for converting the sample rate from the MP3 frames to the requested output sample rate. drmp3_src_config srcConfig; drmp3_zero_object(&srcConfig); srcConfig.sampleRateIn = DR_MP3_DEFAULT_SAMPLE_RATE; @@ -2711,11 +2665,190 @@ drmp3_bool32 drmp3_init_internal(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek drmp3_uninit(pMP3); return DRMP3_FALSE; } + + return DRMP3_TRUE; +} + +static drmp3_uint32 drmp3_decode_next_frame_ex(drmp3* pMP3, drmp3d_sample_t* pPCMFrames, drmp3_bool32 discard) +{ + drmp3_uint32 pcmFramesRead = 0; + + drmp3_assert(pMP3 != NULL); + drmp3_assert(pMP3->onRead != NULL); + + if (pMP3->atEnd) { + return 0; + } + + do { + drmp3dec_frame_info info; + size_t leftoverDataSize; + + /* minimp3 recommends doing data submission in 16K chunks. If we don't have at least 16K bytes available, get more. */ + if (pMP3->dataSize < DRMP3_DATA_CHUNK_SIZE) { + size_t bytesRead; + + if (pMP3->dataCapacity < DRMP3_DATA_CHUNK_SIZE) { + drmp3_uint8* pNewData; + + pMP3->dataCapacity = DRMP3_DATA_CHUNK_SIZE; + pNewData = (drmp3_uint8*)drmp3_realloc(pMP3->pData, pMP3->dataCapacity); + if (pNewData == NULL) { + return 0; /* Out of memory. */ + } + + pMP3->pData = pNewData; + } + + bytesRead = drmp3__on_read(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); + if (bytesRead == 0) { + if (pMP3->dataSize == 0) { + pMP3->atEnd = DRMP3_TRUE; + return 0; /* No data. */ + } + } + + pMP3->dataSize += bytesRead; + } + + if (pMP3->dataSize > INT_MAX) { + pMP3->atEnd = DRMP3_TRUE; + return 0; /* File too big. */ + } + + pcmFramesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->pData, (int)pMP3->dataSize, pPCMFrames, &info); /* <-- Safe size_t -> int conversion thanks to the check above. */ + + /* Consume the data. */ + leftoverDataSize = (pMP3->dataSize - (size_t)info.frame_bytes); + if (info.frame_bytes > 0) { + memmove(pMP3->pData, pMP3->pData + info.frame_bytes, leftoverDataSize); + pMP3->dataSize = leftoverDataSize; + } + + /* + pcmFramesRead will be equal to 0 if decoding failed. If it is zero and info.frame_bytes > 0 then we have successfully + decoded the frame. A special case is if we are wanting to discard the frame, in which case we return successfully. + */ + if (pcmFramesRead > 0 || (info.frame_bytes > 0 && discard)) { + pcmFramesRead = drmp3_hdr_frame_samples(pMP3->decoder.header); + pMP3->pcmFramesConsumedInMP3Frame = 0; + pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead; + pMP3->mp3FrameChannels = info.channels; + pMP3->mp3FrameSampleRate = info.hz; + + /* We need to initialize the resampler if we don't yet have the channel count or sample rate. */ + if (pMP3->channels == 0 || pMP3->sampleRate == 0) { + if (pMP3->channels == 0) { + pMP3->channels = info.channels; + } + if (pMP3->sampleRate == 0) { + pMP3->sampleRate = info.hz; + } + drmp3_init_src(pMP3); + } + + drmp3_src_set_input_sample_rate(&pMP3->src, pMP3->mp3FrameSampleRate); + break; + } else if (info.frame_bytes == 0) { + size_t bytesRead; + + /* Need more data. minimp3 recommends doing data submission in 16K chunks. */ + if (pMP3->dataCapacity == pMP3->dataSize) { + drmp3_uint8* pNewData; + + /* No room. Expand. */ + pMP3->dataCapacity += DRMP3_DATA_CHUNK_SIZE; + pNewData = (drmp3_uint8*)drmp3_realloc(pMP3->pData, pMP3->dataCapacity); + if (pNewData == NULL) { + return 0; /* Out of memory. */ + } + + pMP3->pData = pNewData; + } + + /* Fill in a chunk. */ + bytesRead = drmp3__on_read(pMP3, pMP3->pData + pMP3->dataSize, (pMP3->dataCapacity - pMP3->dataSize)); + if (bytesRead == 0) { + pMP3->atEnd = DRMP3_TRUE; + return 0; /* Error reading more data. */ + } + + pMP3->dataSize += bytesRead; + } + } while (DRMP3_TRUE); + + return pcmFramesRead; +} + +static drmp3_uint32 drmp3_decode_next_frame(drmp3* pMP3) +{ + drmp3_assert(pMP3 != NULL); + return drmp3_decode_next_frame_ex(pMP3, (drmp3d_sample_t*)pMP3->pcmFrames, DRMP3_FALSE); +} + +#if 0 +static drmp3_uint32 drmp3_seek_next_frame(drmp3* pMP3) +{ + drmp3_uint32 pcmFrameCount; + + drmp3_assert(pMP3 != NULL); + + pcmFrameCount = drmp3_decode_next_frame_ex(pMP3, NULL); + if (pcmFrameCount == 0) { + return 0; + } + + /* We have essentially just skipped past the frame, so just set the remaining samples to 0. */ + pMP3->currentPCMFrame += pcmFrameCount; + pMP3->pcmFramesConsumedInMP3Frame = pcmFrameCount; + pMP3->pcmFramesRemainingInMP3Frame = 0; + + return pcmFrameCount; +} +#endif + +drmp3_bool32 drmp3_init_internal(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, const drmp3_config* pConfig) +{ + drmp3_config config; + + drmp3_assert(pMP3 != NULL); + drmp3_assert(onRead != NULL); + + /* This function assumes the output object has already been reset to 0. Do not do that here, otherwise things will break. */ + drmp3dec_init(&pMP3->decoder); + + /* The config can be null in which case we use defaults. */ + if (pConfig != NULL) { + config = *pConfig; + } else { + drmp3_zero_object(&config); + } + + pMP3->channels = config.outputChannels; + + /* Cannot have more than 2 channels. */ + if (pMP3->channels > 2) { + pMP3->channels = 2; + } + + pMP3->sampleRate = config.outputSampleRate; + + pMP3->onRead = onRead; + pMP3->onSeek = onSeek; + pMP3->pUserData = pUserData; + + /* + We need a sample rate converter for converting the sample rate from the MP3 frames to the requested output sample rate. Note that if + we don't yet know the channel count or sample rate we defer this until the first frame is read. + */ + if (pMP3->channels != 0 && pMP3->sampleRate != 0) { + drmp3_init_src(pMP3); + } - // Decode the first frame to confirm that it is indeed a valid MP3 stream. + /* Decode the first frame to confirm that it is indeed a valid MP3 stream. */ if (!drmp3_decode_next_frame(pMP3)) { drmp3_uninit(pMP3); - return DRMP3_FALSE; // Not a valid MP3 stream. + return DRMP3_FALSE; /* Not a valid MP3 stream. */ } return DRMP3_TRUE; @@ -2735,10 +2868,12 @@ drmp3_bool32 drmp3_init(drmp3* pMP3, drmp3_read_proc onRead, drmp3_seek_proc onS static size_t drmp3__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead) { drmp3* pMP3 = (drmp3*)pUserData; + size_t bytesRemaining; + drmp3_assert(pMP3 != NULL); drmp3_assert(pMP3->memory.dataSize >= pMP3->memory.currentReadPos); - size_t bytesRemaining = pMP3->memory.dataSize - pMP3->memory.currentReadPos; + bytesRemaining = pMP3->memory.dataSize - pMP3->memory.currentReadPos; if (bytesToRead > bytesRemaining) { bytesToRead = bytesRemaining; } @@ -2754,26 +2889,27 @@ static size_t drmp3__on_read_memory(void* pUserData, void* pBufferOut, size_t by static drmp3_bool32 drmp3__on_seek_memory(void* pUserData, int byteOffset, drmp3_seek_origin origin) { drmp3* pMP3 = (drmp3*)pUserData; + drmp3_assert(pMP3 != NULL); if (origin == drmp3_seek_origin_current) { if (byteOffset > 0) { if (pMP3->memory.currentReadPos + byteOffset > pMP3->memory.dataSize) { - byteOffset = (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos); // Trying to seek too far forward. + byteOffset = (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos); /* Trying to seek too far forward. */ } } else { if (pMP3->memory.currentReadPos < (size_t)-byteOffset) { - byteOffset = -(int)pMP3->memory.currentReadPos; // Trying to seek too far backwards. + byteOffset = -(int)pMP3->memory.currentReadPos; /* Trying to seek too far backwards. */ } } - // This will never underflow thanks to the clamps above. + /* This will never underflow thanks to the clamps above. */ pMP3->memory.currentReadPos += byteOffset; } else { if ((drmp3_uint32)byteOffset <= pMP3->memory.dataSize) { pMP3->memory.currentReadPos = byteOffset; } else { - pMP3->memory.currentReadPos = pMP3->memory.dataSize; // Trying to seek too far forward. + pMP3->memory.currentReadPos = pMP3->memory.dataSize; /* Trying to seek too far forward. */ } } @@ -2848,21 +2984,22 @@ void drmp3_uninit(drmp3* pMP3) drmp3_uint64 drmp3_read_pcm_frames_f32(drmp3* pMP3, drmp3_uint64 framesToRead, float* pBufferOut) { + drmp3_uint64 totalFramesRead = 0; + if (pMP3 == NULL || pMP3->onRead == NULL) { return 0; } - drmp3_uint64 totalFramesRead = 0; - if (pBufferOut == NULL) { float temp[4096]; while (framesToRead > 0) { + drmp3_uint64 framesJustRead; drmp3_uint64 framesToReadRightNow = sizeof(temp)/sizeof(temp[0]) / pMP3->channels; if (framesToReadRightNow > framesToRead) { framesToReadRightNow = framesToRead; } - drmp3_uint64 framesJustRead = drmp3_read_pcm_frames_f32(pMP3, framesToReadRightNow, temp); + framesJustRead = drmp3_read_pcm_frames_f32(pMP3, framesToReadRightNow, temp); if (framesJustRead == 0) { break; } @@ -2878,6 +3015,41 @@ drmp3_uint64 drmp3_read_pcm_frames_f32(drmp3* pMP3, drmp3_uint64 framesToRead, f return totalFramesRead; } +drmp3_uint64 drmp3_read_pcm_frames_s16(drmp3* pMP3, drmp3_uint64 framesToRead, drmp3_int16* pBufferOut) +{ + float tempF32[4096]; + drmp3_uint64 pcmFramesJustRead; + drmp3_uint64 totalPCMFramesRead = 0; + + if (pMP3 == NULL || pMP3->onRead == NULL) { + return 0; + } + + /* Naive implementation: read into a temp f32 buffer, then convert. */ + for (;;) { + drmp3_uint64 pcmFramesToReadThisIteration = (framesToRead - totalPCMFramesRead); + if (pcmFramesToReadThisIteration > drmp3_countof(tempF32)/pMP3->channels) { + pcmFramesToReadThisIteration = drmp3_countof(tempF32)/pMP3->channels; + } + + pcmFramesJustRead = drmp3_read_pcm_frames_f32(pMP3, pcmFramesToReadThisIteration, tempF32); + if (pcmFramesJustRead == 0) { + break; + } + + drmp3dec_f32_to_s16(tempF32, pBufferOut, (int)(pcmFramesJustRead * pMP3->channels)); /* <-- Safe cast since pcmFramesJustRead will be clamped based on the size of tempF32 which is always small. */ + pBufferOut += pcmFramesJustRead * pMP3->channels; + + totalPCMFramesRead += pcmFramesJustRead; + + if (pcmFramesJustRead < pcmFramesToReadThisIteration) { + break; + } + } + + return totalPCMFramesRead; +} + void drmp3_reset(drmp3* pMP3) { drmp3_assert(pMP3 != NULL); @@ -2896,7 +3068,6 @@ void drmp3_reset(drmp3* pMP3) pMP3->src.algo.linear.alpha = 0; pMP3->src.algo.linear.isNextFramesLoaded = 0; pMP3->src.algo.linear.isPrevFramesLoaded = 0; - //drmp3_zero_object(&pMP3->decoder); drmp3dec_init(&pMP3->decoder); } @@ -2905,12 +3076,12 @@ drmp3_bool32 drmp3_seek_to_start_of_stream(drmp3* pMP3) drmp3_assert(pMP3 != NULL); drmp3_assert(pMP3->onSeek != NULL); - // Seek to the start of the stream to begin with. + /* Seek to the start of the stream to begin with. */ if (!drmp3__on_seek(pMP3, 0, drmp3_seek_origin_start)) { return DRMP3_FALSE; } - // Clear any cached data. + /* Clear any cached data. */ drmp3_reset(pMP3); return DRMP3_TRUE; } @@ -2927,26 +3098,31 @@ float drmp3_get_pcm_frames_remaining_in_mp3_frame(drmp3* pMP3) return frameCountPreSRC * factor; } -// NOTE ON SEEKING -// =============== -// The seeking code below is a complete mess and is broken for cases when the sample rate changes. The problem -// is with the resampling and the crappy resampler used by dr_mp3. What needs to happen is the following: -// -// 1) The resampler needs to be replaced. -// 2) The resampler has state which needs to be updated whenever an MP3 frame is decoded outside of -// drmp3_read_pcm_frames_f32(). The resampler needs an API to "flush" some imaginary input so that it's -// state is updated accordingly. +/* +NOTE ON SEEKING +=============== +The seeking code below is a complete mess and is broken for cases when the sample rate changes. The problem +is with the resampling and the crappy resampler used by dr_mp3. What needs to happen is the following: +1) The resampler needs to be replaced. +2) The resampler has state which needs to be updated whenever an MP3 frame is decoded outside of + drmp3_read_pcm_frames_f32(). The resampler needs an API to "flush" some imaginary input so that it's + state is updated accordingly. +*/ drmp3_bool32 drmp3_seek_forward_by_pcm_frames__brute_force(drmp3* pMP3, drmp3_uint64 frameOffset) { + drmp3_uint64 framesRead; + #if 0 - // MP3 is a bit annoying when it comes to seeking because of the bit reservoir. It basically means that an MP3 frame can possibly - // depend on some of the data of prior frames. This means it's not as simple as seeking to the first byte of the MP3 frame that - // contains the sample because that MP3 frame will need the data from the previous MP3 frame (which we just seeked past!). To - // resolve this we seek past a number of MP3 frames up to a point, and then read-and-discard the remainder. + /* + MP3 is a bit annoying when it comes to seeking because of the bit reservoir. It basically means that an MP3 frame can possibly + depend on some of the data of prior frames. This means it's not as simple as seeking to the first byte of the MP3 frame that + contains the sample because that MP3 frame will need the data from the previous MP3 frame (which we just seeked past!). To + resolve this we seek past a number of MP3 frames up to a point, and then read-and-discard the remainder. + */ drmp3_uint64 maxFramesToReadAndDiscard = (drmp3_uint64)(DRMP3_MAX_PCM_FRAMES_PER_MP3_FRAME * 3 * ((float)pMP3->src.config.sampleRateOut / (float)pMP3->src.config.sampleRateIn)); - // Now get rid of leading whole frames. + /* Now get rid of leading whole frames. */ while (frameOffset > maxFramesToReadAndDiscard) { float pcmFramesRemainingInCurrentMP3FrameF = drmp3_get_pcm_frames_remaining_in_mp3_frame(pMP3); drmp3_uint32 pcmFramesRemainingInCurrentMP3Frame = (drmp3_uint32)pcmFramesRemainingInCurrentMP3FrameF; @@ -2965,14 +3141,14 @@ drmp3_bool32 drmp3_seek_forward_by_pcm_frames__brute_force(drmp3* pMP3, drmp3_ui } } - // The last step is to read-and-discard any remaining PCM frames to make it sample-exact. - drmp3_uint64 framesRead = drmp3_read_pcm_frames_f32(pMP3, frameOffset, NULL); + /* The last step is to read-and-discard any remaining PCM frames to make it sample-exact. */ + framesRead = drmp3_read_pcm_frames_f32(pMP3, frameOffset, NULL); if (framesRead != frameOffset) { return DRMP3_FALSE; } #else - // Just using a dumb read-and-discard for now pending updates to the resampler. - drmp3_uint64 framesRead = drmp3_read_pcm_frames_f32(pMP3, frameOffset, NULL); + /* Just using a dumb read-and-discard for now pending updates to the resampler. */ + framesRead = drmp3_read_pcm_frames_f32(pMP3, frameOffset, NULL); if (framesRead != frameOffset) { return DRMP3_FALSE; } @@ -2989,11 +3165,12 @@ drmp3_bool32 drmp3_seek_to_pcm_frame__brute_force(drmp3* pMP3, drmp3_uint64 fram return DRMP3_TRUE; } - // If we're moving foward we just read from where we're at. Otherwise we need to move back to the start of - // the stream and read from the beginning. - //drmp3_uint64 framesToReadAndDiscard; + /* + If we're moving foward we just read from where we're at. Otherwise we need to move back to the start of + the stream and read from the beginning. + */ if (frameIndex < pMP3->currentPCMFrame) { - // Moving backward. Move to the start of the stream and then move forward. + /* Moving backward. Move to the start of the stream and then move forward. */ if (!drmp3_seek_to_start_of_stream(pMP3)) { return DRMP3_FALSE; } @@ -3005,16 +3182,20 @@ drmp3_bool32 drmp3_seek_to_pcm_frame__brute_force(drmp3* pMP3, drmp3_uint64 fram drmp3_bool32 drmp3_find_closest_seek_point(drmp3* pMP3, drmp3_uint64 frameIndex, drmp3_uint32* pSeekPointIndex) { + drmp3_uint32 iSeekPoint; + drmp3_assert(pSeekPointIndex != NULL); + *pSeekPointIndex = 0; + if (frameIndex < pMP3->pSeekPoints[0].pcmFrameIndex) { return DRMP3_FALSE; } - // Linear search for simplicity to begin with while I'm getting this thing working. Once it's all working change this to a binary search. - for (drmp3_uint32 iSeekPoint = 0; iSeekPoint < pMP3->seekPointCount; ++iSeekPoint) { + /* Linear search for simplicity to begin with while I'm getting this thing working. Once it's all working change this to a binary search. */ + for (iSeekPoint = 0; iSeekPoint < pMP3->seekPointCount; ++iSeekPoint) { if (pMP3->pSeekPoints[iSeekPoint].pcmFrameIndex > frameIndex) { - break; // Found it. + break; /* Found it. */ } *pSeekPointIndex = iSeekPoint; @@ -3025,14 +3206,16 @@ drmp3_bool32 drmp3_find_closest_seek_point(drmp3* pMP3, drmp3_uint64 frameIndex, drmp3_bool32 drmp3_seek_to_pcm_frame__seek_table(drmp3* pMP3, drmp3_uint64 frameIndex) { + drmp3_seek_point seekPoint; + drmp3_uint32 priorSeekPointIndex; + drmp3_uint16 iMP3Frame; + drmp3_uint64 leftoverFrames; + drmp3_assert(pMP3 != NULL); drmp3_assert(pMP3->pSeekPoints != NULL); drmp3_assert(pMP3->seekPointCount > 0); - drmp3_seek_point seekPoint; - - // If there is no prior seekpoint it means the target PCM frame comes before the first seek point. Just assume a seekpoint at the start of the file in this case. - drmp3_uint32 priorSeekPointIndex; + /* If there is no prior seekpoint it means the target PCM frame comes before the first seek point. Just assume a seekpoint at the start of the file in this case. */ if (drmp3_find_closest_seek_point(pMP3, frameIndex, &priorSeekPointIndex)) { seekPoint = pMP3->pSeekPoints[priorSeekPointIndex]; } else { @@ -3042,44 +3225,51 @@ drmp3_bool32 drmp3_seek_to_pcm_frame__seek_table(drmp3* pMP3, drmp3_uint64 frame seekPoint.pcmFramesToDiscard = 0; } - // First thing to do is seek to the first byte of the relevant MP3 frame. + /* First thing to do is seek to the first byte of the relevant MP3 frame. */ if (!drmp3__on_seek_64(pMP3, seekPoint.seekPosInBytes, drmp3_seek_origin_start)) { - return DRMP3_FALSE; // Failed to seek. + return DRMP3_FALSE; /* Failed to seek. */ } - // Clear any cached data. + /* Clear any cached data. */ drmp3_reset(pMP3); - // Whole MP3 frames need to be discarded first. - for (drmp3_uint16 iMP3Frame = 0; iMP3Frame < seekPoint.mp3FramesToDiscard; ++iMP3Frame) { - // Pass in non-null for the last frame because we want to ensure the sample rate converter is preloaded correctly. - drmp3d_sample_t* pPCMFrames = NULL; + /* Whole MP3 frames need to be discarded first. */ + for (iMP3Frame = 0; iMP3Frame < seekPoint.mp3FramesToDiscard; ++iMP3Frame) { + drmp3_uint32 pcmFramesReadPreSRC; + drmp3d_sample_t* pPCMFrames; + + /* Pass in non-null for the last frame because we want to ensure the sample rate converter is preloaded correctly. */ + pPCMFrames = NULL; if (iMP3Frame == seekPoint.mp3FramesToDiscard-1) { pPCMFrames = (drmp3d_sample_t*)pMP3->pcmFrames; } - // We first need to decode the next frame, and then we need to flush the resampler. - drmp3_uint32 pcmFramesReadPreSRC = drmp3_decode_next_frame_ex(pMP3, pPCMFrames, DRMP3_TRUE); + /* We first need to decode the next frame, and then we need to flush the resampler. */ + pcmFramesReadPreSRC = drmp3_decode_next_frame_ex(pMP3, pPCMFrames, DRMP3_TRUE); if (pcmFramesReadPreSRC == 0) { return DRMP3_FALSE; } } - // We seeked to an MP3 frame in the raw stream so we need to make sure the current PCM frame is set correctly. + /* We seeked to an MP3 frame in the raw stream so we need to make sure the current PCM frame is set correctly. */ pMP3->currentPCMFrame = seekPoint.pcmFrameIndex - seekPoint.pcmFramesToDiscard; - // Update resampler. This is wrong. Need to instead update it on a per MP3 frame basis. Also broken for cases when - // the sample rate is being reduced in my testing. Should work fine when the input and output sample rate is the same - // or a clean multiple. + /* + Update resampler. This is wrong. Need to instead update it on a per MP3 frame basis. Also broken for cases when + the sample rate is being reduced in my testing. Should work fine when the input and output sample rate is the same + or a clean multiple. + */ pMP3->src.algo.linear.alpha = pMP3->currentPCMFrame * ((double)pMP3->src.config.sampleRateIn / pMP3->src.config.sampleRateOut); pMP3->src.algo.linear.alpha = pMP3->src.algo.linear.alpha - (drmp3_uint32)(pMP3->src.algo.linear.alpha); if (pMP3->src.algo.linear.alpha > 0) { pMP3->src.algo.linear.isPrevFramesLoaded = 1; } - // Now at this point we can follow the same process as the brute force technique where we just skip over unnecessary MP3 frames and then - // read-and-discard at least 2 whole MP3 frames. - drmp3_uint64 leftoverFrames = frameIndex - pMP3->currentPCMFrame; + /* + Now at this point we can follow the same process as the brute force technique where we just skip over unnecessary MP3 frames and then + read-and-discard at least 2 whole MP3 frames. + */ + leftoverFrames = frameIndex - pMP3->currentPCMFrame; return drmp3_seek_forward_by_pcm_frames__brute_force(pMP3, leftoverFrames); } @@ -3093,7 +3283,7 @@ drmp3_bool32 drmp3_seek_to_pcm_frame(drmp3* pMP3, drmp3_uint64 frameIndex) return drmp3_seek_to_start_of_stream(pMP3); } - // Use the seek table if we have one. + /* Use the seek table if we have one. */ if (pMP3->pSeekPoints != NULL && pMP3->seekPointCount > 0) { return drmp3_seek_to_pcm_frame__seek_table(pMP3, frameIndex); } else { @@ -3103,46 +3293,58 @@ drmp3_bool32 drmp3_seek_to_pcm_frame(drmp3* pMP3, drmp3_uint64 frameIndex) drmp3_bool32 drmp3_get_mp3_and_pcm_frame_count(drmp3* pMP3, drmp3_uint64* pMP3FrameCount, drmp3_uint64* pPCMFrameCount) { + drmp3_uint64 currentPCMFrame; + drmp3_uint64 totalPCMFrameCount; + drmp3_uint64 totalMP3FrameCount; + float totalPCMFrameCountFractionalPart; + if (pMP3 == NULL) { return DRMP3_FALSE; } - // The way this works is we move back to the start of the stream, iterate over each MP3 frame and calculate the frame count based - // on our output sample rate, the seek back to the PCM frame we were sitting on before calling this function. + /* + The way this works is we move back to the start of the stream, iterate over each MP3 frame and calculate the frame count based + on our output sample rate, the seek back to the PCM frame we were sitting on before calling this function. + */ - // The stream must support seeking for this to work. + /* The stream must support seeking for this to work. */ if (pMP3->onSeek == NULL) { return DRMP3_FALSE; } - // We'll need to seek back to where we were, so grab the PCM frame we're currently sitting on so we can restore later. - drmp3_uint64 currentPCMFrame = pMP3->currentPCMFrame; + /* We'll need to seek back to where we were, so grab the PCM frame we're currently sitting on so we can restore later. */ + currentPCMFrame = pMP3->currentPCMFrame; if (!drmp3_seek_to_start_of_stream(pMP3)) { return DRMP3_FALSE; } - drmp3_uint64 totalPCMFrameCount = 0; - drmp3_uint64 totalMP3FrameCount = 0; + totalPCMFrameCount = 0; + totalMP3FrameCount = 0; - float totalPCMFrameCountFractionalPart = 0; // <-- With resampling there will be a fractional part to each MP3 frame that we need to accumulate. + totalPCMFrameCountFractionalPart = 0; /* <-- With resampling there will be a fractional part to each MP3 frame that we need to accumulate. */ for (;;) { - drmp3_uint32 pcmFramesInCurrentMP3FrameIn = drmp3_decode_next_frame_ex(pMP3, NULL, DRMP3_FALSE); + drmp3_uint32 pcmFramesInCurrentMP3FrameIn; + float srcRatio; + float pcmFramesInCurrentMP3FrameOutF; + drmp3_uint32 pcmFramesInCurrentMP3FrameOut; + + pcmFramesInCurrentMP3FrameIn = drmp3_decode_next_frame_ex(pMP3, NULL, DRMP3_FALSE); if (pcmFramesInCurrentMP3FrameIn == 0) { break; } - float srcRatio = (float)pMP3->mp3FrameSampleRate / (float)pMP3->sampleRate; + srcRatio = (float)pMP3->mp3FrameSampleRate / (float)pMP3->sampleRate; drmp3_assert(srcRatio > 0); - float pcmFramesInCurrentMP3FrameOutF = totalPCMFrameCountFractionalPart + (pcmFramesInCurrentMP3FrameIn / srcRatio); - drmp3_uint32 pcmFramesInCurrentMP3FrameOut = (drmp3_uint32)pcmFramesInCurrentMP3FrameOutF; + pcmFramesInCurrentMP3FrameOutF = totalPCMFrameCountFractionalPart + (pcmFramesInCurrentMP3FrameIn / srcRatio); + pcmFramesInCurrentMP3FrameOut = (drmp3_uint32)pcmFramesInCurrentMP3FrameOutF; totalPCMFrameCountFractionalPart = pcmFramesInCurrentMP3FrameOutF - pcmFramesInCurrentMP3FrameOut; totalPCMFrameCount += pcmFramesInCurrentMP3FrameOut; totalMP3FrameCount += 1; } - // Finally, we need to seek back to where we were. + /* Finally, we need to seek back to where we were. */ if (!drmp3_seek_to_start_of_stream(pMP3)) { return DRMP3_FALSE; } @@ -3183,11 +3385,15 @@ drmp3_uint64 drmp3_get_mp3_frame_count(drmp3* pMP3) void drmp3__accumulate_running_pcm_frame_count(drmp3* pMP3, drmp3_uint32 pcmFrameCountIn, drmp3_uint64* pRunningPCMFrameCount, float* pRunningPCMFrameCountFractionalPart) { - float srcRatio = (float)pMP3->mp3FrameSampleRate / (float)pMP3->sampleRate; + float srcRatio; + float pcmFrameCountOutF; + drmp3_uint32 pcmFrameCountOut; + + srcRatio = (float)pMP3->mp3FrameSampleRate / (float)pMP3->sampleRate; drmp3_assert(srcRatio > 0); - float pcmFrameCountOutF = *pRunningPCMFrameCountFractionalPart + (pcmFrameCountIn / srcRatio); - drmp3_uint32 pcmFrameCountOut = (drmp3_uint32)pcmFrameCountOutF; + pcmFrameCountOutF = *pRunningPCMFrameCountFractionalPart + (pcmFrameCountIn / srcRatio); + pcmFrameCountOut = (drmp3_uint32)pcmFrameCountOutF; *pRunningPCMFrameCountFractionalPart = pcmFrameCountOutF - pcmFrameCountOut; *pRunningPCMFrameCount += pcmFrameCountOut; } @@ -3195,31 +3401,34 @@ void drmp3__accumulate_running_pcm_frame_count(drmp3* pMP3, drmp3_uint32 pcmFram typedef struct { drmp3_uint64 bytePos; - drmp3_uint64 pcmFrameIndex; // <-- After sample rate conversion. + drmp3_uint64 pcmFrameIndex; /* <-- After sample rate conversion. */ } drmp3__seeking_mp3_frame_info; drmp3_bool32 drmp3_calculate_seek_points(drmp3* pMP3, drmp3_uint32* pSeekPointCount, drmp3_seek_point* pSeekPoints) { - if (pMP3 == NULL || pSeekPointCount == NULL || pSeekPoints == NULL) { - return DRMP3_FALSE; // Invalid args. - } - - drmp3_uint32 seekPointCount = *pSeekPointCount; - if (seekPointCount == 0) { - return DRMP3_FALSE; // The client has requested no seek points. Consider this to be invalid arguments since the client has probably not intended this. - } - - // We'll need to seek back to the current sample after calculating the seekpoints so we need to go ahead and grab the current location at the top. - drmp3_uint64 currentPCMFrame = pMP3->currentPCMFrame; - - // We never do more than the total number of MP3 frames and we limit it to 32-bits. + drmp3_uint32 seekPointCount; + drmp3_uint64 currentPCMFrame; drmp3_uint64 totalMP3FrameCount; drmp3_uint64 totalPCMFrameCount; + + if (pMP3 == NULL || pSeekPointCount == NULL || pSeekPoints == NULL) { + return DRMP3_FALSE; /* Invalid args. */ + } + + seekPointCount = *pSeekPointCount; + if (seekPointCount == 0) { + return DRMP3_FALSE; /* The client has requested no seek points. Consider this to be invalid arguments since the client has probably not intended this. */ + } + + /* We'll need to seek back to the current sample after calculating the seekpoints so we need to go ahead and grab the current location at the top. */ + currentPCMFrame = pMP3->currentPCMFrame; + + /* We never do more than the total number of MP3 frames and we limit it to 32-bits. */ if (!drmp3_get_mp3_and_pcm_frame_count(pMP3, &totalMP3FrameCount, &totalPCMFrameCount)) { return DRMP3_FALSE; } - // If there's less than DRMP3_SEEK_LEADING_MP3_FRAMES+1 frames we just report 1 seek point which will be the very start of the stream. + /* If there's less than DRMP3_SEEK_LEADING_MP3_FRAMES+1 frames we just report 1 seek point which will be the very start of the stream. */ if (totalMP3FrameCount < DRMP3_SEEK_LEADING_MP3_FRAMES+1) { seekPointCount = 1; pSeekPoints[0].seekPosInBytes = 0; @@ -3227,69 +3436,88 @@ drmp3_bool32 drmp3_calculate_seek_points(drmp3* pMP3, drmp3_uint32* pSeekPointCo pSeekPoints[0].mp3FramesToDiscard = 0; pSeekPoints[0].pcmFramesToDiscard = 0; } else { + drmp3_uint64 pcmFramesBetweenSeekPoints; + drmp3__seeking_mp3_frame_info mp3FrameInfo[DRMP3_SEEK_LEADING_MP3_FRAMES+1]; + drmp3_uint64 runningPCMFrameCount = 0; + float runningPCMFrameCountFractionalPart = 0; + drmp3_uint64 nextTargetPCMFrame; + drmp3_uint32 iMP3Frame; + drmp3_uint32 iSeekPoint; + if (seekPointCount > totalMP3FrameCount-1) { seekPointCount = (drmp3_uint32)totalMP3FrameCount-1; } - drmp3_uint64 pcmFramesBetweenSeekPoints = totalPCMFrameCount / (seekPointCount+1); + pcmFramesBetweenSeekPoints = totalPCMFrameCount / (seekPointCount+1); - // Here is where we actually calculate the seek points. We need to start by moving the start of the stream. We then enumerate over each - // MP3 frame. + /* + Here is where we actually calculate the seek points. We need to start by moving the start of the stream. We then enumerate over each + MP3 frame. + */ if (!drmp3_seek_to_start_of_stream(pMP3)) { return DRMP3_FALSE; } - // We need to cache the byte positions of the previous MP3 frames. As a new MP3 frame is iterated, we cycle the byte positions in this - // array. The value in the first item in this array is the byte position that will be reported in the next seek point. - drmp3__seeking_mp3_frame_info mp3FrameInfo[DRMP3_SEEK_LEADING_MP3_FRAMES+1]; + /* + We need to cache the byte positions of the previous MP3 frames. As a new MP3 frame is iterated, we cycle the byte positions in this + array. The value in the first item in this array is the byte position that will be reported in the next seek point. + */ - drmp3_uint64 runningPCMFrameCount = 0; - float runningPCMFrameCountFractionalPart = 0; + /* We need to initialize the array of MP3 byte positions for the leading MP3 frames. */ + for (iMP3Frame = 0; iMP3Frame < DRMP3_SEEK_LEADING_MP3_FRAMES+1; ++iMP3Frame) { + drmp3_uint32 pcmFramesInCurrentMP3FrameIn; - // We need to initialize the array of MP3 byte positions for the leading MP3 frames. - for (int iMP3Frame = 0; iMP3Frame < DRMP3_SEEK_LEADING_MP3_FRAMES+1; ++iMP3Frame) { - // The byte position of the next frame will be the stream's cursor position, minus whatever is sitting in the buffer. + /* The byte position of the next frame will be the stream's cursor position, minus whatever is sitting in the buffer. */ drmp3_assert(pMP3->streamCursor >= pMP3->dataSize); mp3FrameInfo[iMP3Frame].bytePos = pMP3->streamCursor - pMP3->dataSize; mp3FrameInfo[iMP3Frame].pcmFrameIndex = runningPCMFrameCount; - // We need to get information about this frame so we can know how many samples it contained. - drmp3_uint32 pcmFramesInCurrentMP3FrameIn = drmp3_decode_next_frame_ex(pMP3, NULL, DRMP3_FALSE); + /* We need to get information about this frame so we can know how many samples it contained. */ + pcmFramesInCurrentMP3FrameIn = drmp3_decode_next_frame_ex(pMP3, NULL, DRMP3_FALSE); if (pcmFramesInCurrentMP3FrameIn == 0) { - return DRMP3_FALSE; // This should never happen. + return DRMP3_FALSE; /* This should never happen. */ } drmp3__accumulate_running_pcm_frame_count(pMP3, pcmFramesInCurrentMP3FrameIn, &runningPCMFrameCount, &runningPCMFrameCountFractionalPart); } - // At this point we will have extracted the byte positions of the leading MP3 frames. We can now start iterating over each seek point and - // calculate them. - drmp3_uint64 nextTargetPCMFrame = 0; - for (drmp3_uint32 iSeekPoint = 0; iSeekPoint < seekPointCount; ++iSeekPoint) { + /* + At this point we will have extracted the byte positions of the leading MP3 frames. We can now start iterating over each seek point and + calculate them. + */ + nextTargetPCMFrame = 0; + for (iSeekPoint = 0; iSeekPoint < seekPointCount; ++iSeekPoint) { nextTargetPCMFrame += pcmFramesBetweenSeekPoints; for (;;) { if (nextTargetPCMFrame < runningPCMFrameCount) { - // The next seek point is in the current MP3 frame. + /* The next seek point is in the current MP3 frame. */ pSeekPoints[iSeekPoint].seekPosInBytes = mp3FrameInfo[0].bytePos; pSeekPoints[iSeekPoint].pcmFrameIndex = nextTargetPCMFrame; pSeekPoints[iSeekPoint].mp3FramesToDiscard = DRMP3_SEEK_LEADING_MP3_FRAMES; pSeekPoints[iSeekPoint].pcmFramesToDiscard = (drmp3_uint16)(nextTargetPCMFrame - mp3FrameInfo[DRMP3_SEEK_LEADING_MP3_FRAMES-1].pcmFrameIndex); break; } else { - // The next seek point is not in the current MP3 frame, so continue on to the next one. The first thing to do is cycle the cached - // MP3 frame info. - for (size_t i = 0; i < drmp3_countof(mp3FrameInfo)-1; ++i) { + size_t i; + drmp3_uint32 pcmFramesInCurrentMP3FrameIn; + + /* + The next seek point is not in the current MP3 frame, so continue on to the next one. The first thing to do is cycle the cached + MP3 frame info. + */ + for (i = 0; i < drmp3_countof(mp3FrameInfo)-1; ++i) { mp3FrameInfo[i] = mp3FrameInfo[i+1]; } - // Cache previous MP3 frame info. + /* Cache previous MP3 frame info. */ mp3FrameInfo[drmp3_countof(mp3FrameInfo)-1].bytePos = pMP3->streamCursor - pMP3->dataSize; mp3FrameInfo[drmp3_countof(mp3FrameInfo)-1].pcmFrameIndex = runningPCMFrameCount; - // Go to the next MP3 frame. This shouldn't ever fail, but just in case it does we just set the seek point and break. If it happens, it - // should only ever do it for the last seek point. - drmp3_uint32 pcmFramesInCurrentMP3FrameIn = drmp3_decode_next_frame_ex(pMP3, NULL, DRMP3_TRUE); + /* + Go to the next MP3 frame. This shouldn't ever fail, but just in case it does we just set the seek point and break. If it happens, it + should only ever do it for the last seek point. + */ + pcmFramesInCurrentMP3FrameIn = drmp3_decode_next_frame_ex(pMP3, NULL, DRMP3_TRUE); if (pcmFramesInCurrentMP3FrameIn == 0) { pSeekPoints[iSeekPoint].seekPosInBytes = mp3FrameInfo[0].bytePos; pSeekPoints[iSeekPoint].pcmFrameIndex = nextTargetPCMFrame; @@ -3303,7 +3531,7 @@ drmp3_bool32 drmp3_calculate_seek_points(drmp3* pMP3, drmp3_uint32* pSeekPointCo } } - // Finally, we need to seek back to where we were. + /* Finally, we need to seek back to where we were. */ if (!drmp3_seek_to_start_of_stream(pMP3)) { return DRMP3_FALSE; } @@ -3323,11 +3551,11 @@ drmp3_bool32 drmp3_bind_seek_table(drmp3* pMP3, drmp3_uint32 seekPointCount, drm } if (seekPointCount == 0 || pSeekPoints == NULL) { - // Unbinding. + /* Unbinding. */ pMP3->seekPointCount = 0; pMP3->pSeekPoints = NULL; } else { - // Binding. + /* Binding. */ pMP3->seekPointCount = seekPointCount; pMP3->pSeekPoints = pSeekPoints; } @@ -3338,13 +3566,13 @@ drmp3_bool32 drmp3_bind_seek_table(drmp3* pMP3, drmp3_uint32 seekPointCount, drm float* drmp3__full_read_and_close_f32(drmp3* pMP3, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount) { - drmp3_assert(pMP3 != NULL); - drmp3_uint64 totalFramesRead = 0; drmp3_uint64 framesCapacity = 0; float* pFrames = NULL; - float temp[4096]; + + drmp3_assert(pMP3 != NULL); + for (;;) { drmp3_uint64 framesToReadRightNow = drmp3_countof(temp) / pMP3->channels; drmp3_uint64 framesJustRead = drmp3_read_pcm_frames_f32(pMP3, framesToReadRightNow, temp); @@ -3352,19 +3580,22 @@ float* drmp3__full_read_and_close_f32(drmp3* pMP3, drmp3_config* pConfig, drmp3_ break; } - // Reallocate the output buffer if there's not enough room. + /* Reallocate the output buffer if there's not enough room. */ if (framesCapacity < totalFramesRead + framesJustRead) { + drmp3_uint64 newFramesBufferSize; + float* pNewFrames; + framesCapacity *= 2; if (framesCapacity < totalFramesRead + framesJustRead) { framesCapacity = totalFramesRead + framesJustRead; } - drmp3_uint64 newFramesBufferSize = framesCapacity*pMP3->channels*sizeof(float); + newFramesBufferSize = framesCapacity*pMP3->channels*sizeof(float); if (newFramesBufferSize > DRMP3_SIZE_MAX) { break; } - float* pNewFrames = (float*)drmp3_realloc(pFrames, (size_t)newFramesBufferSize); + pNewFrames = (float*)drmp3_realloc(pFrames, (size_t)newFramesBufferSize); if (pNewFrames == NULL) { drmp3_free(pFrames); break; @@ -3376,7 +3607,7 @@ float* drmp3__full_read_and_close_f32(drmp3* pMP3, drmp3_config* pConfig, drmp3_ drmp3_copy_memory(pFrames + totalFramesRead*pMP3->channels, temp, (size_t)(framesJustRead*pMP3->channels*sizeof(float))); totalFramesRead += framesJustRead; - // If the number of frames we asked for is less that what we actually read it means we've reached the end. + /* If the number of frames we asked for is less that what we actually read it means we've reached the end. */ if (framesJustRead != framesToReadRightNow) { break; } @@ -3389,10 +3620,77 @@ float* drmp3__full_read_and_close_f32(drmp3* pMP3, drmp3_config* pConfig, drmp3_ drmp3_uninit(pMP3); - if (pTotalFrameCount) *pTotalFrameCount = totalFramesRead; + if (pTotalFrameCount) { + *pTotalFrameCount = totalFramesRead; + } + return pFrames; } +drmp3_int16* drmp3__full_read_and_close_s16(drmp3* pMP3, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount) +{ + drmp3_uint64 totalFramesRead = 0; + drmp3_uint64 framesCapacity = 0; + drmp3_int16* pFrames = NULL; + drmp3_int16 temp[4096]; + + drmp3_assert(pMP3 != NULL); + + for (;;) { + drmp3_uint64 framesToReadRightNow = drmp3_countof(temp) / pMP3->channels; + drmp3_uint64 framesJustRead = drmp3_read_pcm_frames_s16(pMP3, framesToReadRightNow, temp); + if (framesJustRead == 0) { + break; + } + + /* Reallocate the output buffer if there's not enough room. */ + if (framesCapacity < totalFramesRead + framesJustRead) { + drmp3_uint64 newFramesBufferSize; + drmp3_int16* pNewFrames; + + framesCapacity *= 2; + if (framesCapacity < totalFramesRead + framesJustRead) { + framesCapacity = totalFramesRead + framesJustRead; + } + + newFramesBufferSize = framesCapacity*pMP3->channels*sizeof(drmp3_int16); + if (newFramesBufferSize > DRMP3_SIZE_MAX) { + break; + } + + pNewFrames = (drmp3_int16*)drmp3_realloc(pFrames, (size_t)newFramesBufferSize); + if (pNewFrames == NULL) { + drmp3_free(pFrames); + break; + } + + pFrames = pNewFrames; + } + + drmp3_copy_memory(pFrames + totalFramesRead*pMP3->channels, temp, (size_t)(framesJustRead*pMP3->channels*sizeof(drmp3_int16))); + totalFramesRead += framesJustRead; + + /* If the number of frames we asked for is less that what we actually read it means we've reached the end. */ + if (framesJustRead != framesToReadRightNow) { + break; + } + } + + if (pConfig != NULL) { + pConfig->outputChannels = pMP3->channels; + pConfig->outputSampleRate = pMP3->sampleRate; + } + + drmp3_uninit(pMP3); + + if (pTotalFrameCount) { + *pTotalFrameCount = totalFramesRead; + } + + return pFrames; +} + + float* drmp3_open_and_read_f32(drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount) { drmp3 mp3; @@ -3403,6 +3701,17 @@ float* drmp3_open_and_read_f32(drmp3_read_proc onRead, drmp3_seek_proc onSeek, v return drmp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount); } +drmp3_int16* drmp3_open_and_read_s16(drmp3_read_proc onRead, drmp3_seek_proc onSeek, void* pUserData, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount) +{ + drmp3 mp3; + if (!drmp3_init(&mp3, onRead, onSeek, pUserData, pConfig)) { + return NULL; + } + + return drmp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount); +} + + float* drmp3_open_memory_and_read_f32(const void* pData, size_t dataSize, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount) { drmp3 mp3; @@ -3413,6 +3722,17 @@ float* drmp3_open_memory_and_read_f32(const void* pData, size_t dataSize, drmp3_ return drmp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount); } +drmp3_int16* drmp3_open_memory_and_read_s16(const void* pData, size_t dataSize, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount) +{ + drmp3 mp3; + if (!drmp3_init_memory(&mp3, pData, dataSize, pConfig)) { + return NULL; + } + + return drmp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount); +} + + #ifndef DR_MP3_NO_STDIO float* drmp3_open_file_and_read_f32(const char* filePath, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount) { @@ -3423,6 +3743,16 @@ float* drmp3_open_file_and_read_f32(const char* filePath, drmp3_config* pConfig, return drmp3__full_read_and_close_f32(&mp3, pConfig, pTotalFrameCount); } + +drmp3_int16* drmp3_open_file_and_read_s16(const char* filePath, drmp3_config* pConfig, drmp3_uint64* pTotalFrameCount) +{ + drmp3 mp3; + if (!drmp3_init_file(&mp3, filePath, pConfig)) { + return NULL; + } + + return drmp3__full_read_and_close_s16(&mp3, pConfig, pTotalFrameCount); +} #endif void drmp3_free(void* p) @@ -3432,130 +3762,169 @@ void drmp3_free(void* p) #endif /*DR_MP3_IMPLEMENTATION*/ - -// DIFFERENCES BETWEEN minimp3 AND dr_mp3 -// ====================================== -// - First, keep in mind that minimp3 (https://github.com/lieff/minimp3) is where all the real work was done. All of the -// code relating to the actual decoding remains mostly unmodified, apart from some namespacing changes. -// - dr_mp3 adds a pulling style API which allows you to deliver raw data via callbacks. So, rather than pushing data -// to the decoder, the decoder _pulls_ data from your callbacks. -// - In addition to callbacks, a decoder can be initialized from a block of memory and a file. -// - The dr_mp3 pull API reads PCM frames rather than whole MP3 frames. -// - dr_mp3 adds convenience APIs for opening and decoding entire files in one go. -// - dr_mp3 is fully namespaced, including the implementation section, which is more suitable when compiling projects -// as a single translation unit (aka unity builds). At the time of writing this, a unity build is not possible when -// using minimp3 in conjunction with stb_vorbis. dr_mp3 addresses this. - - -// REVISION HISTORY -// ================ -// -// v0.4.1 - 2018-12-30 -// - Fix a warning. -// -// v0.4.0 - 2018-12-16 -// - API CHANGE: Rename some APIs: -// - drmp3_read_f32 -> to drmp3_read_pcm_frames_f32 -// - drmp3_seek_to_frame -> drmp3_seek_to_pcm_frame -// - drmp3_open_and_decode_f32 -> drmp3_open_and_read_f32 -// - drmp3_open_and_decode_memory_f32 -> drmp3_open_memory_and_read_f32 -// - drmp3_open_and_decode_file_f32 -> drmp3_open_file_and_read_f32 -// - Add drmp3_get_pcm_frame_count(). -// - Add drmp3_get_mp3_frame_count(). -// - Improve seeking performance. -// -// v0.3.2 - 2018-09-11 -// - Fix a couple of memory leaks. -// - Bring up to date with minimp3. -// -// v0.3.1 - 2018-08-25 -// - Fix C++ build. -// -// v0.3.0 - 2018-08-25 -// - Bring up to date with minimp3. This has a minor API change: the "pcm" parameter of drmp3dec_decode_frame() has -// been changed from short* to void* because it can now output both s16 and f32 samples, depending on whether or -// not the DR_MP3_FLOAT_OUTPUT option is set. -// -// v0.2.11 - 2018-08-08 -// - Fix a bug where the last part of a file is not read. -// -// v0.2.10 - 2018-08-07 -// - Improve 64-bit detection. -// -// v0.2.9 - 2018-08-05 -// - Fix C++ build on older versions of GCC. -// - Bring up to date with minimp3. -// -// v0.2.8 - 2018-08-02 -// - Fix compilation errors with older versions of GCC. -// -// v0.2.7 - 2018-07-13 -// - Bring up to date with minimp3. -// -// v0.2.6 - 2018-07-12 -// - Bring up to date with minimp3. -// -// v0.2.5 - 2018-06-22 -// - Bring up to date with minimp3. -// -// v0.2.4 - 2018-05-12 -// - Bring up to date with minimp3. -// -// v0.2.3 - 2018-04-29 -// - Fix TCC build. -// -// v0.2.2 - 2018-04-28 -// - Fix bug when opening a decoder from memory. -// -// v0.2.1 - 2018-04-27 -// - Efficiency improvements when the decoder reaches the end of the stream. -// -// v0.2 - 2018-04-21 -// - Bring up to date with minimp3. -// - Start using major.minor.revision versioning. -// -// v0.1d - 2018-03-30 -// - Bring up to date with minimp3. -// -// v0.1c - 2018-03-11 -// - Fix C++ build error. -// -// v0.1b - 2018-03-07 -// - Bring up to date with minimp3. -// -// v0.1a - 2018-02-28 -// - Fix compilation error on GCC/Clang. -// - Fix some warnings. -// -// v0.1 - 2018-02-xx -// - Initial versioned release. - +/* +DIFFERENCES BETWEEN minimp3 AND dr_mp3 +====================================== +- First, keep in mind that minimp3 (https://github.com/lieff/minimp3) is where all the real work was done. All of the + code relating to the actual decoding remains mostly unmodified, apart from some namespacing changes. +- dr_mp3 adds a pulling style API which allows you to deliver raw data via callbacks. So, rather than pushing data + to the decoder, the decoder _pulls_ data from your callbacks. +- In addition to callbacks, a decoder can be initialized from a block of memory and a file. +- The dr_mp3 pull API reads PCM frames rather than whole MP3 frames. +- dr_mp3 adds convenience APIs for opening and decoding entire files in one go. +- dr_mp3 is fully namespaced, including the implementation section, which is more suitable when compiling projects + as a single translation unit (aka unity builds). At the time of writing this, a unity build is not possible when + using minimp3 in conjunction with stb_vorbis. dr_mp3 addresses this. +*/ /* +REVISION HISTORY +================ +v0.4.3 - 2019-05-05 + - Use the channel count and/or sample rate of the first MP3 frame instead of DR_MP3_DEFAULT_CHANNELS and + DR_MP3_DEFAULT_SAMPLE_RATE when they are set to 0. To use the old behaviour, just set the relevant property to + DR_MP3_DEFAULT_CHANNELS or DR_MP3_DEFAULT_SAMPLE_RATE. + - Add s16 reading APIs + - drmp3_read_pcm_frames_s16 + - drmp3_open_memory_and_read_s16 + - drmp3_open_and_read_s16 + - drmp3_open_file_and_read_s16 + - Add drmp3_get_mp3_and_pcm_frame_count() to the public header section. + - Add support for C89. + - Change license to choice of public domain or MIT-0. + +v0.4.2 - 2019-02-21 + - Fix a warning. + +v0.4.1 - 2018-12-30 + - Fix a warning. + +v0.4.0 - 2018-12-16 + - API CHANGE: Rename some APIs: + - drmp3_read_f32 -> to drmp3_read_pcm_frames_f32 + - drmp3_seek_to_frame -> drmp3_seek_to_pcm_frame + - drmp3_open_and_decode_f32 -> drmp3_open_and_read_f32 + - drmp3_open_and_decode_memory_f32 -> drmp3_open_memory_and_read_f32 + - drmp3_open_and_decode_file_f32 -> drmp3_open_file_and_read_f32 + - Add drmp3_get_pcm_frame_count(). + - Add drmp3_get_mp3_frame_count(). + - Improve seeking performance. + +v0.3.2 - 2018-09-11 + - Fix a couple of memory leaks. + - Bring up to date with minimp3. + +v0.3.1 - 2018-08-25 + - Fix C++ build. + +v0.3.0 - 2018-08-25 + - Bring up to date with minimp3. This has a minor API change: the "pcm" parameter of drmp3dec_decode_frame() has + been changed from short* to void* because it can now output both s16 and f32 samples, depending on whether or + not the DR_MP3_FLOAT_OUTPUT option is set. + +v0.2.11 - 2018-08-08 + - Fix a bug where the last part of a file is not read. + +v0.2.10 - 2018-08-07 + - Improve 64-bit detection. + +v0.2.9 - 2018-08-05 + - Fix C++ build on older versions of GCC. + - Bring up to date with minimp3. + +v0.2.8 - 2018-08-02 + - Fix compilation errors with older versions of GCC. + +v0.2.7 - 2018-07-13 + - Bring up to date with minimp3. + +v0.2.6 - 2018-07-12 + - Bring up to date with minimp3. + +v0.2.5 - 2018-06-22 + - Bring up to date with minimp3. + +v0.2.4 - 2018-05-12 + - Bring up to date with minimp3. + +v0.2.3 - 2018-04-29 + - Fix TCC build. + +v0.2.2 - 2018-04-28 + - Fix bug when opening a decoder from memory. + +v0.2.1 - 2018-04-27 + - Efficiency improvements when the decoder reaches the end of the stream. + +v0.2 - 2018-04-21 + - Bring up to date with minimp3. + - Start using major.minor.revision versioning. + +v0.1d - 2018-03-30 + - Bring up to date with minimp3. + +v0.1c - 2018-03-11 + - Fix C++ build error. + +v0.1b - 2018-03-07 + - Bring up to date with minimp3. + +v0.1a - 2018-02-28 + - Fix compilation error on GCC/Clang. + - Fix some warnings. + +v0.1 - 2018-02-xx + - Initial versioned release. +*/ + +/* +This software is available as a choice of the following licenses. Choose +whichever you prefer. + +=============================================================================== +ALTERNATIVE 1 - Public Domain (www.unlicense.org) +=============================================================================== This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to + +=============================================================================== +ALTERNATIVE 2 - MIT No Attribution +=============================================================================== +Copyright 2018 David Reid + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. */ /* diff --git a/extras/dr_wav.h b/extras/dr_wav.h index ac4f6b54..b2395bfb 100644 --- a/extras/dr_wav.h +++ b/extras/dr_wav.h @@ -1,7 +1,9 @@ -// WAV audio loader and writer. Public domain. See "unlicense" statement at the end of this file. -// dr_wav - v0.9.0 - 2018-12-16 -// -// David Reid - mackron@gmail.com +/* +WAV audio loader and writer. Choice of public domain or MIT-0. See license statements at the end of this file. +dr_wav - v0.9.1 - 2019-05-05 + +David Reid - mackron@gmail.com +*/ /* DEPRECATED APIS @@ -38,112 +40,115 @@ These APIs will be removed completely in version 0.10.0. You can continue to use reading. */ -// USAGE -// -// This is a single-file library. To use it, do something like the following in one .c file. -// #define DR_WAV_IMPLEMENTATION -// #include "dr_wav.h" -// -// You can then #include this file in other parts of the program as you would with any other header file. Do something -// like the following to read audio data: -// -// drwav wav; -// if (!drwav_init_file(&wav, "my_song.wav")) { -// // Error opening WAV file. -// } -// -// drwav_int32* pDecodedInterleavedSamples = malloc(wav.totalPCMFrameCount * wav.channels * sizeof(drwav_int32)); -// size_t numberOfSamplesActuallyDecoded = drwav_read_pcm_frames_s32(&wav, wav.totalPCMFrameCount, pDecodedInterleavedSamples); -// -// ... -// -// drwav_uninit(&wav); -// -// You can also use drwav_open() to allocate and initialize the loader for you: -// -// drwav* pWav = drwav_open_file("my_song.wav"); -// if (pWav == NULL) { -// // Error opening WAV file. -// } -// -// ... -// -// drwav_close(pWav); -// -// If you just want to quickly open and read the audio data in a single operation you can do something like this: -// -// unsigned int channels; -// unsigned int sampleRate; -// drwav_uint64 totalPCMFrameCount; -// float* pSampleData = drwav_open_file_and_read_pcm_frames_f32("my_song.wav", &channels, &sampleRate, &totalPCMFrameCount); -// if (pSampleData == NULL) { -// // Error opening and reading WAV file. -// } -// -// ... -// -// drwav_free(pSampleData); -// -// The examples above use versions of the API that convert the audio data to a consistent format (32-bit signed PCM, in -// this case), but you can still output the audio data in its internal format (see notes below for supported formats): -// -// size_t samplesRead = drwav_read_pcm_frames(&wav, wav.totalPCMFrameCount, pDecodedInterleavedSamples); -// -// You can also read the raw bytes of audio data, which could be useful if dr_wav does not have native support for -// a particular data format: -// -// size_t bytesRead = drwav_read_raw(&wav, bytesToRead, pRawDataBuffer); -// -// -// dr_wav can also be used to output WAV files. This does not currently support compressed formats. To use this, look at -// drwav_open_write(), drwav_open_file_write(), etc. Use drwav_write_pcm_frames() to write samples, or drwav_write_raw() -// to write raw data in the "data" chunk. -// -// drwav_data_format format; -// format.container = drwav_container_riff; // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64. -// format.format = DR_WAVE_FORMAT_PCM; // <-- Any of the DR_WAVE_FORMAT_* codes. -// format.channels = 2; -// format.sampleRate = 44100; -// format.bitsPerSample = 16; -// drwav* pWav = drwav_open_file_write("data/recording.wav", &format); -// -// ... -// -// drwav_uint64 samplesWritten = drwav_write_pcm_frames(pWav, frameCount, pSamples); -// -// -// dr_wav has seamless support the Sony Wave64 format. The decoder will automatically detect it and it should Just Work -// without any manual intervention. -// -// -// OPTIONS -// #define these options before including this file. -// -// #define DR_WAV_NO_CONVERSION_API -// Disables conversion APIs such as drwav_read_pcm_frames_f32() and drwav_s16_to_f32(). -// -// #define DR_WAV_NO_STDIO -// Disables drwav_open_file(), drwav_open_file_write(), etc. -// -// -// -// QUICK NOTES -// - Samples are always interleaved. -// - The default read function does not do any data conversion. Use drwav_read_pcm_frames_f32(), drwav_read_pcm_frames_s32() -// and drwav_read_pcm_frames_s16() to read and convert audio data to 32-bit floating point, signed 32-bit integer and -// signed 16-bit integer samples respectively. Tested and supported internal formats include the following: -// - Unsigned 8-bit PCM -// - Signed 12-bit PCM -// - Signed 16-bit PCM -// - Signed 24-bit PCM -// - Signed 32-bit PCM -// - IEEE 32-bit floating point -// - IEEE 64-bit floating point -// - A-law and u-law -// - Microsoft ADPCM -// - IMA ADPCM (DVI, format code 0x11) -// - dr_wav will try to read the WAV file as best it can, even if it's not strictly conformant to the WAV format. +/* +USAGE +===== +This is a single-file library. To use it, do something like the following in one .c file. + #define DR_WAV_IMPLEMENTATION + #include "dr_wav.h" +You can then #include this file in other parts of the program as you would with any other header file. Do something +like the following to read audio data: + + drwav wav; + if (!drwav_init_file(&wav, "my_song.wav")) { + // Error opening WAV file. + } + + drwav_int32* pDecodedInterleavedSamples = malloc(wav.totalPCMFrameCount * wav.channels * sizeof(drwav_int32)); + size_t numberOfSamplesActuallyDecoded = drwav_read_pcm_frames_s32(&wav, wav.totalPCMFrameCount, pDecodedInterleavedSamples); + + ... + + drwav_uninit(&wav); + +You can also use drwav_open() to allocate and initialize the loader for you: + + drwav* pWav = drwav_open_file("my_song.wav"); + if (pWav == NULL) { + // Error opening WAV file. + } + + ... + + drwav_close(pWav); + +If you just want to quickly open and read the audio data in a single operation you can do something like this: + + unsigned int channels; + unsigned int sampleRate; + drwav_uint64 totalPCMFrameCount; + float* pSampleData = drwav_open_file_and_read_pcm_frames_f32("my_song.wav", &channels, &sampleRate, &totalPCMFrameCount); + if (pSampleData == NULL) { + // Error opening and reading WAV file. + } + + ... + + drwav_free(pSampleData); + +The examples above use versions of the API that convert the audio data to a consistent format (32-bit signed PCM, in +this case), but you can still output the audio data in its internal format (see notes below for supported formats): + + size_t samplesRead = drwav_read_pcm_frames(&wav, wav.totalPCMFrameCount, pDecodedInterleavedSamples); + +You can also read the raw bytes of audio data, which could be useful if dr_wav does not have native support for +a particular data format: + + size_t bytesRead = drwav_read_raw(&wav, bytesToRead, pRawDataBuffer); + + +dr_wav can also be used to output WAV files. This does not currently support compressed formats. To use this, look at +drwav_open_write(), drwav_open_file_write(), etc. Use drwav_write_pcm_frames() to write samples, or drwav_write_raw() +to write raw data in the "data" chunk. + + drwav_data_format format; + format.container = drwav_container_riff; // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64. + format.format = DR_WAVE_FORMAT_PCM; // <-- Any of the DR_WAVE_FORMAT_* codes. + format.channels = 2; + format.sampleRate = 44100; + format.bitsPerSample = 16; + drwav* pWav = drwav_open_file_write("data/recording.wav", &format); + + ... + + drwav_uint64 samplesWritten = drwav_write_pcm_frames(pWav, frameCount, pSamples); + + +dr_wav has seamless support the Sony Wave64 format. The decoder will automatically detect it and it should Just Work +without any manual intervention. + + +OPTIONS +======= +#define these options before including this file. + +#define DR_WAV_NO_CONVERSION_API + Disables conversion APIs such as drwav_read_pcm_frames_f32() and drwav_s16_to_f32(). + +#define DR_WAV_NO_STDIO + Disables drwav_open_file(), drwav_open_file_write(), etc. + + + +QUICK NOTES +=========== +- Samples are always interleaved. +- The default read function does not do any data conversion. Use drwav_read_pcm_frames_f32(), drwav_read_pcm_frames_s32() + and drwav_read_pcm_frames_s16() to read and convert audio data to 32-bit floating point, signed 32-bit integer and + signed 16-bit integer samples respectively. Tested and supported internal formats include the following: + - Unsigned 8-bit PCM + - Signed 12-bit PCM + - Signed 16-bit PCM + - Signed 24-bit PCM + - Signed 32-bit PCM + - IEEE 32-bit floating point + - IEEE 64-bit floating point + - A-law and u-law + - Microsoft ADPCM + - IMA ADPCM (DVI, format code 0x11) +- dr_wav will try to read the WAV file as best it can, even if it's not strictly conformant to the WAV format. +*/ #ifndef dr_wav_h #define dr_wav_h @@ -179,7 +184,7 @@ typedef drwav_uint32 drwav_bool32; extern "C" { #endif -// Common data formats. +/* Common data formats. */ #define DR_WAVE_FORMAT_PCM 0x1 #define DR_WAVE_FORMAT_ADPCM 0x2 #define DR_WAVE_FORMAT_IEEE_FLOAT 0x3 @@ -188,12 +193,12 @@ extern "C" { #define DR_WAVE_FORMAT_DVI_ADPCM 0x11 #define DR_WAVE_FORMAT_EXTENSIBLE 0xFFFE -// Constants. +/* Constants. */ #ifndef DRWAV_MAX_SMPL_LOOPS #define DRWAV_MAX_SMPL_LOOPS 1 #endif -// Flags to pass into drwav_init_ex(), etc. +/* Flags to pass into drwav_init_ex(), etc. */ #define DRWAV_SEQUENTIAL 0x00000001 typedef enum @@ -216,66 +221,76 @@ typedef struct drwav_uint8 guid[16]; } id; - // The size in bytes of the chunk. + /* The size in bytes of the chunk. */ drwav_uint64 sizeInBytes; - // RIFF = 2 byte alignment. - // W64 = 8 byte alignment. + /* + RIFF = 2 byte alignment. + W64 = 8 byte alignment. + */ unsigned int paddingSize; } drwav_chunk_header; -// Callback for when data is read. Return value is the number of bytes actually read. -// -// pUserData [in] The user data that was passed to drwav_init(), drwav_open() and family. -// pBufferOut [out] The output buffer. -// bytesToRead [in] The number of bytes to read. -// -// Returns the number of bytes actually read. -// -// 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. +/* +Callback for when data is read. Return value is the number of bytes actually read. + +pUserData [in] The user data that was passed to drwav_init(), drwav_open() and family. +pBufferOut [out] The output buffer. +bytesToRead [in] The number of bytes to read. + +Returns the number of bytes actually read. + +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 (* drwav_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); -// Callback for when data is written. Returns value is the number of bytes actually written. -// -// pUserData [in] The user data that was passed to drwav_init_write(), drwav_open_write() and family. -// pData [out] A pointer to the data to write. -// bytesToWrite [in] The number of bytes to write. -// -// Returns the number of bytes actually written. -// -// If the return value differs from bytesToWrite, it indicates an error. +/* +Callback for when data is written. Returns value is the number of bytes actually written. + +pUserData [in] The user data that was passed to drwav_init_write(), drwav_open_write() and family. +pData [out] A pointer to the data to write. +bytesToWrite [in] The number of bytes to write. + +Returns the number of bytes actually written. + +If the return value differs from bytesToWrite, it indicates an error. +*/ typedef size_t (* drwav_write_proc)(void* pUserData, const void* pData, size_t bytesToWrite); -// Callback for when data needs to be seeked. -// -// pUserData [in] The user data that was passed to drwav_init(), drwav_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. -// -// Returns whether or not the seek was successful. -// -// Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which -// will be either drwav_seek_origin_start or drwav_seek_origin_current. +/* +Callback for when data needs to be seeked. + +pUserData [in] The user data that was passed to drwav_init(), drwav_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. + +Returns whether or not the seek was successful. + +Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which +will be either drwav_seek_origin_start or drwav_seek_origin_current. +*/ typedef drwav_bool32 (* drwav_seek_proc)(void* pUserData, int offset, drwav_seek_origin origin); -// Callback for when drwav_init_ex/drwav_open_ex finds a chunk. -// -// pChunkUserData [in] The user data that was passed to the pChunkUserData parameter of drwav_init_ex(), drwav_open_ex() and family. -// onRead [in] A pointer to the function to call when reading. -// onSeek [in] A pointer to the function to call when seeking. -// pReadSeekUserData [in] The user data that was passed to the pReadSeekUserData parameter of drwav_init_ex(), drwav_open_ex() and family. -// pChunkHeader [in] A pointer to an object containing basic header information about the chunk. Use this to identify the chunk. -// -// Returns the number of bytes read + seeked. -// -// To read data from the chunk, call onRead(), passing in pReadSeekUserData as the first parameter. Do the same -// for seeking with onSeek(). The return value must be the total number of bytes you have read _plus_ seeked. -// -// You must not attempt to read beyond the boundary of the chunk. +/* +Callback for when drwav_init_ex/drwav_open_ex finds a chunk. + +pChunkUserData [in] The user data that was passed to the pChunkUserData parameter of drwav_init_ex(), drwav_open_ex() and family. +onRead [in] A pointer to the function to call when reading. +onSeek [in] A pointer to the function to call when seeking. +pReadSeekUserData [in] The user data that was passed to the pReadSeekUserData parameter of drwav_init_ex(), drwav_open_ex() and family. +pChunkHeader [in] A pointer to an object containing basic header information about the chunk. Use this to identify the chunk. + +Returns the number of bytes read + seeked. + +To read data from the chunk, call onRead(), passing in pReadSeekUserData as the first parameter. Do the same +for seeking with onSeek(). The return value must be the total number of bytes you have read _plus_ seeked. + +You must not attempt to read beyond the boundary of the chunk. +*/ typedef drwav_uint64 (* drwav_chunk_proc)(void* pChunkUserData, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pReadSeekUserData, const drwav_chunk_header* pChunkHeader); -// Structure for internal use. Only used for loaders opened with drwav_open_memory(). +/* Structure for internal use. Only used for loaders opened with drwav_open_memory(). */ typedef struct { const drwav_uint8* data; @@ -283,7 +298,7 @@ typedef struct size_t currentReadPos; } drwav__memory_stream; -// Structure for internal use. Only used for writers opened with drwav_open_memory_write(). +/* Structure for internal use. Only used for writers opened with drwav_open_memory_write(). */ typedef struct { void** ppData; @@ -295,8 +310,8 @@ typedef struct typedef struct { - drwav_container container; // RIFF, W64. - drwav_uint32 format; // DR_WAVE_FORMAT_* + drwav_container container; /* RIFF, W64. */ + drwav_uint32 format; /* DR_WAVE_FORMAT_* */ drwav_uint32 channels; drwav_uint32 sampleRate; drwav_uint32 bitsPerSample; @@ -304,37 +319,41 @@ typedef struct typedef struct { - // The format tag exactly as specified in the wave file's "fmt" chunk. This can be used by applications - // that require support for data formats not natively supported by dr_wav. + /* + The format tag exactly as specified in the wave file's "fmt" chunk. This can be used by applications + that require support for data formats not natively supported by dr_wav. + */ drwav_uint16 formatTag; - // The number of channels making up the audio data. When this is set to 1 it is mono, 2 is stereo, etc. + /* The number of channels making up the audio data. When this is set to 1 it is mono, 2 is stereo, etc. */ drwav_uint16 channels; - // The sample rate. Usually set to something like 44100. + /* The sample rate. Usually set to something like 44100. */ drwav_uint32 sampleRate; - // Average bytes per second. You probably don't need this, but it's left here for informational purposes. + /* Average bytes per second. You probably don't need this, but it's left here for informational purposes. */ drwav_uint32 avgBytesPerSec; - // Block align. This is equal to the number of channels * bytes per sample. + /* Block align. This is equal to the number of channels * bytes per sample. */ drwav_uint16 blockAlign; - // Bits per sample. + /* Bits per sample. */ drwav_uint16 bitsPerSample; - // The size of the extended data. Only used internally for validation, but left here for informational purposes. + /* The size of the extended data. Only used internally for validation, but left here for informational purposes. */ drwav_uint16 extendedSize; - // The number of valid bits per sample. When is equal to WAVE_FORMAT_EXTENSIBLE, - // is always rounded up to the nearest multiple of 8. This variable contains information about exactly how - // many bits a valid per sample. Mainly used for informational purposes. + /* + The number of valid bits per sample. When is equal to WAVE_FORMAT_EXTENSIBLE, + is always rounded up to the nearest multiple of 8. This variable contains information about exactly how + many bits a valid per sample. Mainly used for informational purposes. + */ drwav_uint16 validBitsPerSample; - // The channel mask. Not used at the moment. + /* The channel mask. Not used at the moment. */ drwav_uint32 channelMask; - // The sub-format, exactly as specified by the wave file. + /* The sub-format, exactly as specified by the wave file. */ drwav_uint8 subFormat[16]; } drwav_fmt; @@ -364,441 +383,483 @@ typedef struct typedef struct { - // A pointer to the function to call when more data is needed. + /* A pointer to the function to call when more data is needed. */ drwav_read_proc onRead; - // A pointer to the function to call when data needs to be written. Only used when the drwav object is opened in write mode. + /* A pointer to the function to call when data needs to be written. Only used when the drwav object is opened in write mode. */ drwav_write_proc onWrite; - // A pointer to the function to call when the wav file needs to be seeked. + /* A pointer to the function to call when the wav file needs to be seeked. */ drwav_seek_proc onSeek; - // The user data to pass to callbacks. + /* The user data to pass to callbacks. */ void* pUserData; - // Whether or not the WAV file is formatted as a standard RIFF file or W64. + /* Whether or not the WAV file is formatted as a standard RIFF file or W64. */ drwav_container container; - // Structure containing format information exactly as specified by the wav file. + /* Structure containing format information exactly as specified by the wav file. */ drwav_fmt fmt; - // The sample rate. Will be set to something like 44100. + /* The sample rate. Will be set to something like 44100. */ drwav_uint32 sampleRate; - // The number of channels. This will be set to 1 for monaural streams, 2 for stereo, etc. + /* The number of channels. This will be set to 1 for monaural streams, 2 for stereo, etc. */ drwav_uint16 channels; - // The bits per sample. Will be set to something like 16, 24, etc. + /* The bits per sample. Will be set to something like 16, 24, etc. */ drwav_uint16 bitsPerSample; - // Equal to fmt.formatTag, or the value specified by fmt.subFormat if fmt.formatTag is equal to 65534 (WAVE_FORMAT_EXTENSIBLE). + /* Equal to fmt.formatTag, or the value specified by fmt.subFormat if fmt.formatTag is equal to 65534 (WAVE_FORMAT_EXTENSIBLE). */ drwav_uint16 translatedFormatTag; - // The total number of PCM frames making up the audio data. + /* The total number of PCM frames making up the audio data. */ drwav_uint64 totalPCMFrameCount; - // The size in bytes of the data chunk. + /* The size in bytes of the data chunk. */ drwav_uint64 dataChunkDataSize; - // The position in the stream of the first byte of the data chunk. This is used for seeking. + /* The position in the stream of the first byte of the data chunk. This is used for seeking. */ drwav_uint64 dataChunkDataPos; - // The number of bytes remaining in the data chunk. + /* The number of bytes remaining in the data chunk. */ drwav_uint64 bytesRemaining; - // Only used in sequential write mode. Keeps track of the desired size of the "data" chunk at the point of initialization time. Always - // set to 0 for non-sequential writes and when the drwav object is opened in read mode. Used for validation. + /* + Only used in sequential write mode. Keeps track of the desired size of the "data" chunk at the point of initialization time. Always + set to 0 for non-sequential writes and when the drwav object is opened in read mode. Used for validation. + */ drwav_uint64 dataChunkDataSizeTargetWrite; - // Keeps track of whether or not the wav writer was initialized in sequential mode. + /* Keeps track of whether or not the wav writer was initialized in sequential mode. */ drwav_bool32 isSequentialWrite; - // smpl chunk. + /* smpl chunk. */ drwav_smpl smpl; - // A hack to avoid a DRWAV_MALLOC() when opening a decoder with drwav_open_memory(). + /* A hack to avoid a DRWAV_MALLOC() when opening a decoder with drwav_open_memory(). */ drwav__memory_stream memoryStream; drwav__memory_stream_write memoryStreamWrite; - // Generic data for compressed formats. This data is shared across all block-compressed formats. + /* Generic data for compressed formats. This data is shared across all block-compressed formats. */ struct { - drwav_uint64 iCurrentSample; // The index of the next sample that will be read by drwav_read_*(). This is used with "totalSampleCount" to ensure we don't read excess samples at the end of the last block. + drwav_uint64 iCurrentSample; /* The index of the next sample that will be read by drwav_read_*(). This is used with "totalSampleCount" to ensure we don't read excess samples at the end of the last block. */ } compressed; - // Microsoft ADPCM specific data. + /* Microsoft ADPCM specific data. */ struct { drwav_uint32 bytesRemainingInBlock; drwav_uint16 predictor[2]; drwav_int32 delta[2]; - drwav_int32 cachedSamples[4]; // Samples are stored in this cache during decoding. + drwav_int32 cachedSamples[4]; /* Samples are stored in this cache during decoding. */ drwav_uint32 cachedSampleCount; - drwav_int32 prevSamples[2][2]; // The previous 2 samples for each channel (2 channels at most). + drwav_int32 prevSamples[2][2]; /* The previous 2 samples for each channel (2 channels at most). */ } msadpcm; - // IMA ADPCM specific data. + /* IMA ADPCM specific data. */ struct { drwav_uint32 bytesRemainingInBlock; drwav_int32 predictor[2]; drwav_int32 stepIndex[2]; - drwav_int32 cachedSamples[16]; // Samples are stored in this cache during decoding. + drwav_int32 cachedSamples[16]; /* Samples are stored in this cache during decoding. */ drwav_uint32 cachedSampleCount; } ima; - drwav_uint64 totalSampleCount; // <-- DEPRECATED. Will be removed in a future version. + drwav_uint64 totalSampleCount; /* <-- DEPRECATED. Will be removed in a future version. */ } drwav; -// Initializes a pre-allocated drwav object. -// -// pWav [out] A pointer to the drwav object being initialized. -// 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. -// onChunk [in, optional] The function to call when a chunk is enumerated at initialized time. -// pUserData, pReadSeekUserData [in, optional] A pointer to application defined data that will be passed to onRead and onSeek. -// pChunkUserData [in, optional] A pointer to application defined data that will be passed to onChunk. -// flags [in, optional] A set of flags for controlling how things are loaded. -// -// Returns true if successful; false otherwise. -// -// Close the loader with drwav_uninit(). -// -// This is the lowest level function for initializing a WAV file. You can also use drwav_init_file() and drwav_init_memory() -// to open the stream from a file or from a block of memory respectively. -// -// If you want dr_wav to manage the memory allocation for you, consider using drwav_open() instead. This will allocate -// a drwav object on the heap and return a pointer to it. -// -// Possible values for flags: -// DRWAV_SEQUENTIAL: Never perform a backwards seek while loading. This disables the chunk callback and will cause this function -// to return as soon as the data chunk is found. Any chunks after the data chunk will be ignored. -// -// drwav_init() is equivalent to "drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0);". -// -// The onChunk callback is not called for the WAVE or FMT chunks. The contents of the FMT chunk can be read from pWav->fmt -// after the function returns. -// -// See also: drwav_init_file(), drwav_init_memory(), drwav_uninit() +/* +Initializes a pre-allocated drwav object. + +pWav [out] A pointer to the drwav object being initialized. +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. +onChunk [in, optional] The function to call when a chunk is enumerated at initialized time. +pUserData, pReadSeekUserData [in, optional] A pointer to application defined data that will be passed to onRead and onSeek. +pChunkUserData [in, optional] A pointer to application defined data that will be passed to onChunk. +flags [in, optional] A set of flags for controlling how things are loaded. + +Returns true if successful; false otherwise. + +Close the loader with drwav_uninit(). + +This is the lowest level function for initializing a WAV file. You can also use drwav_init_file() and drwav_init_memory() +to open the stream from a file or from a block of memory respectively. + +If you want dr_wav to manage the memory allocation for you, consider using drwav_open() instead. This will allocate +a drwav object on the heap and return a pointer to it. + +Possible values for flags: + DRWAV_SEQUENTIAL: Never perform a backwards seek while loading. This disables the chunk callback and will cause this function + to return as soon as the data chunk is found. Any chunks after the data chunk will be ignored. + +drwav_init() is equivalent to "drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0);". + +The onChunk callback is not called for the WAVE or FMT chunks. The contents of the FMT chunk can be read from pWav->fmt +after the function returns. + +See also: drwav_init_file(), drwav_init_memory(), drwav_uninit() +*/ drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData); drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, drwav_uint32 flags); -// Initializes a pre-allocated drwav object for writing. -// -// onWrite [in] The function to call when data needs to be written. -// onSeek [in] The function to call when the write position needs to move. -// pUserData [in, optional] A pointer to application defined data that will be passed to onWrite and onSeek. -// -// Returns true if successful; false otherwise. -// -// Close the writer with drwav_uninit(). -// -// This is the lowest level function for initializing a WAV file. You can also use drwav_init_file() and drwav_init_memory() -// to open the stream from a file or from a block of memory respectively. -// -// If the total sample count is known, you can use drwav_init_write_sequential(). This avoids the need for dr_wav to perform -// a post-processing step for storing the total sample count and the size of the data chunk which requires a backwards seek. -// -// If you want dr_wav to manage the memory allocation for you, consider using drwav_open() instead. This will allocate -// a drwav object on the heap and return a pointer to it. -// -// See also: drwav_init_file_write(), drwav_init_memory_write(), drwav_uninit() +/* +Initializes a pre-allocated drwav object for writing. + +onWrite [in] The function to call when data needs to be written. +onSeek [in] The function to call when the write position needs to move. +pUserData [in, optional] A pointer to application defined data that will be passed to onWrite and onSeek. + +Returns true if successful; false otherwise. + +Close the writer with drwav_uninit(). + +This is the lowest level function for initializing a WAV file. You can also use drwav_init_file() and drwav_init_memory() +to open the stream from a file or from a block of memory respectively. + +If the total sample count is known, you can use drwav_init_write_sequential(). This avoids the need for dr_wav to perform +a post-processing step for storing the total sample count and the size of the data chunk which requires a backwards seek. + +If you want dr_wav to manage the memory allocation for you, consider using drwav_open() instead. This will allocate +a drwav object on the heap and return a pointer to it. + +See also: drwav_init_file_write(), drwav_init_memory_write(), drwav_uninit() +*/ drwav_bool32 drwav_init_write(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData); drwav_bool32 drwav_init_write_sequential(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_write_proc onWrite, void* pUserData); -// Uninitializes the given drwav object. -// -// Use this only for objects initialized with drwav_init(). +/* +Uninitializes the given drwav object. + +Use this only for objects initialized with drwav_init(). +*/ void drwav_uninit(drwav* pWav); -// Opens a wav file using the given callbacks. -// -// 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. -// -// Returns null on error. -// -// Close the loader with drwav_close(). -// -// You can also use drwav_open_file() and drwav_open_memory() to open the stream from a file or from a block of -// memory respectively. -// -// This is different from drwav_init() in that it will allocate the drwav object for you via DRWAV_MALLOC() before -// initializing it. -// -// See also: drwav_init(), drwav_open_file(), drwav_open_memory(), drwav_close() +/* +Opens a wav file using the given callbacks. + +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. + +Returns null on error. + +Close the loader with drwav_close(). + +You can also use drwav_open_file() and drwav_open_memory() to open the stream from a file or from a block of +memory respectively. + +This is different from drwav_init() in that it will allocate the drwav object for you via DRWAV_MALLOC() before +initializing it. + +See also: drwav_init(), drwav_open_file(), drwav_open_memory(), drwav_close() +*/ drwav* drwav_open(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData); drwav* drwav_open_ex(drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, drwav_uint32 flags); -// Opens a wav file for writing using the given callbacks. -// -// onWrite [in] The function to call when data needs to be written. -// onSeek [in] The function to call when the write position needs to move. -// pUserData [in, optional] A pointer to application defined data that will be passed to onWrite and onSeek. -// -// Returns null on error. -// -// Close the loader with drwav_close(). -// -// You can also use drwav_open_file_write() and drwav_open_memory_write() to open the stream from a file or from a block -// of memory respectively. -// -// This is different from drwav_init_write() in that it will allocate the drwav object for you via DRWAV_MALLOC() before -// initializing it. -// -// See also: drwav_open_file_write(), drwav_open_memory_write(), drwav_close() +/* +Opens a wav file for writing using the given callbacks. + +onWrite [in] The function to call when data needs to be written. +onSeek [in] The function to call when the write position needs to move. +pUserData [in, optional] A pointer to application defined data that will be passed to onWrite and onSeek. + +Returns null on error. + +Close the loader with drwav_close(). + +You can also use drwav_open_file_write() and drwav_open_memory_write() to open the stream from a file or from a block +of memory respectively. + +This is different from drwav_init_write() in that it will allocate the drwav object for you via DRWAV_MALLOC() before +initializing it. + +See also: drwav_open_file_write(), drwav_open_memory_write(), drwav_close() +*/ drwav* drwav_open_write(const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData); drwav* drwav_open_write_sequential(const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_write_proc onWrite, void* pUserData); -// Uninitializes and deletes the the given drwav object. -// -// Use this only for objects created with drwav_open(). +/* +Uninitializes and deletes the the given drwav object. + +Use this only for objects created with drwav_open(). +*/ void drwav_close(drwav* pWav); -// Reads raw audio data. -// -// This is the lowest level function for reading audio data. It simply reads the given number of -// bytes of the raw internal sample data. -// -// Consider using drwav_read_pcm_frames_s16(), drwav_read_pcm_frames_s32() or drwav_read_pcm_frames_f32() for -// reading sample data in a consistent format. -// -// Returns the number of bytes actually read. +/* +Reads raw audio data. + +This is the lowest level function for reading audio data. It simply reads the given number of +bytes of the raw internal sample data. + +Consider using drwav_read_pcm_frames_s16(), drwav_read_pcm_frames_s32() or drwav_read_pcm_frames_f32() for +reading sample data in a consistent format. + +Returns the number of bytes actually read. +*/ size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut); -// Reads a chunk of audio data in the native internal format. -// -// This is typically the most efficient way to retrieve audio data, but it does not do any format -// conversions which means you'll need to convert the data manually if required. -// -// If the return value is less than it means the end of the file has been reached or -// you have requested more samples than can possibly fit in the output buffer. -// -// This function will only work when sample data is of a fixed size and uncompressed. If you are -// using a compressed format consider using drwav_read_raw() or drwav_read_pcm_frames_s16/s32/f32/etc(). +/* +Reads a chunk of audio data in the native internal format. + +This is typically the most efficient way to retrieve audio data, but it does not do any format +conversions which means you'll need to convert the data manually if required. + +If the return value is less than it means the end of the file has been reached or +you have requested more samples than can possibly fit in the output buffer. + +This function will only work when sample data is of a fixed size and uncompressed. If you are +using a compressed format consider using drwav_read_raw() or drwav_read_pcm_frames_s16/s32/f32/etc(). +*/ drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut); -// Seeks to the given PCM frame. -// -// Returns true if successful; false otherwise. +/* +Seeks to the given PCM frame. + +Returns true if successful; false otherwise. +*/ drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex); -// Writes raw audio data. -// -// Returns the number of bytes actually written. If this differs from bytesToWrite, it indicates an error. +/* +Writes raw audio data. + +Returns the number of bytes actually written. If this differs from bytesToWrite, it indicates an error. +*/ size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData); -// Writes PCM frames. -// -// Returns the number of PCM frames written. +/* +Writes PCM frames. + +Returns the number of PCM frames written. +*/ drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData); -//// Conversion Utilities //// +/* Conversion Utilities */ #ifndef DR_WAV_NO_CONVERSION_API -// Reads a chunk of audio data and converts it to signed 16-bit PCM samples. -// -// Returns the number of PCM frames actually read. -// -// If the return value is less than it means the end of the file has been reached. +/* +Reads a chunk of audio data and converts it to signed 16-bit PCM samples. + +Returns the number of PCM frames actually read. + +If the return value is less than it means the end of the file has been reached. +*/ drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut); -// Low-level function for converting unsigned 8-bit PCM samples to signed 16-bit PCM samples. +/* Low-level function for converting unsigned 8-bit PCM samples to signed 16-bit PCM samples. */ void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); -// Low-level function for converting signed 24-bit PCM samples to signed 16-bit PCM samples. +/* Low-level function for converting signed 24-bit PCM samples to signed 16-bit PCM samples. */ void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); -// Low-level function for converting signed 32-bit PCM samples to signed 16-bit PCM samples. +/* Low-level function for converting signed 32-bit PCM samples to signed 16-bit PCM samples. */ void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount); -// Low-level function for converting IEEE 32-bit floating point samples to signed 16-bit PCM samples. +/* Low-level function for converting IEEE 32-bit floating point samples to signed 16-bit PCM samples. */ void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount); -// Low-level function for converting IEEE 64-bit floating point samples to signed 16-bit PCM samples. +/* Low-level function for converting IEEE 64-bit floating point samples to signed 16-bit PCM samples. */ void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount); -// Low-level function for converting A-law samples to signed 16-bit PCM samples. +/* Low-level function for converting A-law samples to signed 16-bit PCM samples. */ void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); -// Low-level function for converting u-law samples to signed 16-bit PCM samples. +/* Low-level function for converting u-law samples to signed 16-bit PCM samples. */ void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); +/* +Reads a chunk of audio data and converts it to IEEE 32-bit floating point samples. -// Reads a chunk of audio data and converts it to IEEE 32-bit floating point samples. -// -// Returns the number of PCM frames actually read. -// -// If the return value is less than it means the end of the file has been reached. +Returns the number of PCM frames actually read. + +If the return value is less than it means the end of the file has been reached. +*/ drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut); -// Low-level function for converting unsigned 8-bit PCM samples to IEEE 32-bit floating point samples. +/* Low-level function for converting unsigned 8-bit PCM samples to IEEE 32-bit floating point samples. */ void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); -// Low-level function for converting signed 16-bit PCM samples to IEEE 32-bit floating point samples. +/* Low-level function for converting signed 16-bit PCM samples to IEEE 32-bit floating point samples. */ void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount); -// Low-level function for converting signed 24-bit PCM samples to IEEE 32-bit floating point samples. +/* Low-level function for converting signed 24-bit PCM samples to IEEE 32-bit floating point samples. */ void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); -// Low-level function for converting signed 32-bit PCM samples to IEEE 32-bit floating point samples. +/* Low-level function for converting signed 32-bit PCM samples to IEEE 32-bit floating point samples. */ void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount); -// Low-level function for converting IEEE 64-bit floating point samples to IEEE 32-bit floating point samples. +/* Low-level function for converting IEEE 64-bit floating point samples to IEEE 32-bit floating point samples. */ void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount); -// Low-level function for converting A-law samples to IEEE 32-bit floating point samples. +/* Low-level function for converting A-law samples to IEEE 32-bit floating point samples. */ void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); -// Low-level function for converting u-law samples to IEEE 32-bit floating point samples. +/* Low-level function for converting u-law samples to IEEE 32-bit floating point samples. */ void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); +/* +Reads a chunk of audio data and converts it to signed 32-bit PCM samples. -// Reads a chunk of audio data and converts it to signed 32-bit PCM samples. -// -// Returns the number of PCM frames actually read. -// -// If the return value is less than it means the end of the file has been reached. +Returns the number of PCM frames actually read. + +If the return value is less than it means the end of the file has been reached. +*/ drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut); -// Low-level function for converting unsigned 8-bit PCM samples to signed 32-bit PCM samples. +/* Low-level function for converting unsigned 8-bit PCM samples to signed 32-bit PCM samples. */ void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); -// Low-level function for converting signed 16-bit PCM samples to signed 32-bit PCM samples. +/* Low-level function for converting signed 16-bit PCM samples to signed 32-bit PCM samples. */ void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount); -// Low-level function for converting signed 24-bit PCM samples to signed 32-bit PCM samples. +/* Low-level function for converting signed 24-bit PCM samples to signed 32-bit PCM samples. */ void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); -// Low-level function for converting IEEE 32-bit floating point samples to signed 32-bit PCM samples. +/* Low-level function for converting IEEE 32-bit floating point samples to signed 32-bit PCM samples. */ void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount); -// Low-level function for converting IEEE 64-bit floating point samples to signed 32-bit PCM samples. +/* Low-level function for converting IEEE 64-bit floating point samples to signed 32-bit PCM samples. */ void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount); -// Low-level function for converting A-law samples to signed 32-bit PCM samples. +/* Low-level function for converting A-law samples to signed 32-bit PCM samples. */ void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); -// Low-level function for converting u-law samples to signed 32-bit PCM samples. +/* Low-level function for converting u-law samples to signed 32-bit PCM samples. */ void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); -#endif //DR_WAV_NO_CONVERSION_API +#endif /* DR_WAV_NO_CONVERSION_API */ -//// High-Level Convenience Helpers //// +/* High-Level Convenience Helpers */ #ifndef DR_WAV_NO_STDIO +/* +Helper for initializing a wave file using stdio. -// Helper for initializing a wave file using stdio. -// -// This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav -// objects because the operating system may restrict the number of file handles an application can have open at -// any given time. +This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav +objects because the operating system may restrict the number of file handles an application can have open at +any given time. +*/ drwav_bool32 drwav_init_file(drwav* pWav, const char* filename); drwav_bool32 drwav_init_file_ex(drwav* pWav, const char* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags); -// Helper for initializing a wave file for writing using stdio. -// -// This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav -// objects because the operating system may restrict the number of file handles an application can have open at -// any given time. +/* +Helper for initializing a wave file for writing using stdio. + +This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav +objects because the operating system may restrict the number of file handles an application can have open at +any given time. +*/ drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat); drwav_bool32 drwav_init_file_write_sequential(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount); -// Helper for opening a wave file using stdio. -// -// This holds the internal FILE object until drwav_close() is called. Keep this in mind if you're caching drwav -// objects because the operating system may restrict the number of file handles an application can have open at -// any given time. +/* +Helper for opening a wave file using stdio. + +This holds the internal FILE object until drwav_close() is called. Keep this in mind if you're caching drwav +objects because the operating system may restrict the number of file handles an application can have open at +any given time. +*/ drwav* drwav_open_file(const char* filename); drwav* drwav_open_file_ex(const char* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags); -// Helper for opening a wave file for writing using stdio. -// -// This holds the internal FILE object until drwav_close() is called. Keep this in mind if you're caching drwav -// objects because the operating system may restrict the number of file handles an application can have open at -// any given time. +/* +Helper for opening a wave file for writing using stdio. + +This holds the internal FILE object until drwav_close() is called. Keep this in mind if you're caching drwav +objects because the operating system may restrict the number of file handles an application can have open at +any given time. +*/ drwav* drwav_open_file_write(const char* filename, const drwav_data_format* pFormat); drwav* drwav_open_file_write_sequential(const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount); -#endif //DR_WAV_NO_STDIO +#endif /* DR_WAV_NO_STDIO */ -// Helper for initializing a loader from a pre-allocated memory buffer. -// -// This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for -// the lifetime of the drwav object. -// -// The buffer should contain the contents of the entire wave file, not just the sample data. +/* +Helper for initializing a loader from a pre-allocated memory buffer. + +This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for +the lifetime of the drwav object. + +The buffer should contain the contents of the entire wave file, not just the sample data. +*/ drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize); drwav_bool32 drwav_init_memory_ex(drwav* pWav, const void* data, size_t dataSize, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags); -// Helper for initializing a writer which outputs data to a memory buffer. -// -// dr_wav will manage the memory allocations, however it is up to the caller to free the data with drwav_free(). -// -// The buffer will remain allocated even after drwav_uninit() is called. Indeed, the buffer should not be -// considered valid until after drwav_uninit() has been called anyway. +/* +Helper for initializing a writer which outputs data to a memory buffer. + +dr_wav will manage the memory allocations, however it is up to the caller to free the data with drwav_free(). + +The buffer will remain allocated even after drwav_uninit() is called. Indeed, the buffer should not be +considered valid until after drwav_uninit() has been called anyway. +*/ drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat); drwav_bool32 drwav_init_memory_write_sequential(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount); -// Helper for opening a loader from a pre-allocated memory buffer. -// -// This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for -// the lifetime of the drwav object. -// -// The buffer should contain the contents of the entire wave file, not just the sample data. +/* +Helper for opening a loader from a pre-allocated memory buffer. + +This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for +the lifetime of the drwav object. + +The buffer should contain the contents of the entire wave file, not just the sample data. +*/ drwav* drwav_open_memory(const void* data, size_t dataSize); drwav* drwav_open_memory_ex(const void* data, size_t dataSize, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags); -// Helper for opening a writer which outputs data to a memory buffer. -// -// dr_wav will manage the memory allocations, however it is up to the caller to free the data with drwav_free(). -// -// The buffer will remain allocated even after drwav_close() is called. Indeed, the buffer should not be -// considered valid until after drwav_close() has been called anyway. +/* +Helper for opening a writer which outputs data to a memory buffer. + +dr_wav will manage the memory allocations, however it is up to the caller to free the data with drwav_free(). + +The buffer will remain allocated even after drwav_close() is called. Indeed, the buffer should not be +considered valid until after drwav_close() has been called anyway. +*/ drwav* drwav_open_memory_write(void** ppData, size_t* pDataSize, const drwav_data_format* pFormat); drwav* drwav_open_memory_write_sequential(void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount); #ifndef DR_WAV_NO_CONVERSION_API -// Opens and reads a wav file in a single operation. +/* Opens and reads a wav file in a single operation. */ drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount); float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount); drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount); #ifndef DR_WAV_NO_STDIO -// Opens and decodes a wav file in a single operation. +/* Opens and decodes a wav file in a single operation. */ drwav_int16* drwav_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount); float* drwav_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount); drwav_int32* drwav_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount); #endif -// Opens and decodes a wav file from a block of memory in a single operation. +/* Opens and decodes a wav file from a block of memory in a single operation. */ drwav_int16* drwav_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount); float* drwav_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount); drwav_int32* drwav_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount); #endif -// Frees data that was allocated internally by dr_wav. +/* Frees data that was allocated internally by dr_wav. */ void drwav_free(void* pDataReturnedByOpenAndRead); -// DEPRECATED APIS -// =============== +/* DEPRECATED APIS */ drwav_uint64 drwav_read(drwav* pWav, drwav_uint64 samplesToRead, void* pBufferOut); drwav_uint64 drwav_read_s16(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut); drwav_uint64 drwav_read_f32(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut); @@ -823,25 +884,26 @@ drwav_int32* drwav_open_memory_and_read_s32(const void* data, size_t dataSize, u #ifdef __cplusplus } #endif -#endif // dr_wav_h +#endif /* dr_wav_h */ -///////////////////////////////////////////////////// -// -// IMPLEMENTATION -// -///////////////////////////////////////////////////// +/************************************************************************************************************************************************************ + ************************************************************************************************************************************************************ + IMPLEMENTATION + + ************************************************************************************************************************************************************ + ************************************************************************************************************************************************************/ #ifdef DR_WAV_IMPLEMENTATION #include -#include // For memcpy(), memset() -#include // For INT_MAX +#include /* For memcpy(), memset() */ +#include /* For INT_MAX */ #ifndef DR_WAV_NO_STDIO #include #endif -// Standard library stuff. +/* Standard library stuff. */ #ifndef DRWAV_ASSERT #include #define DRWAV_ASSERT(expression) assert(expression) @@ -880,15 +942,15 @@ typedef drwav_int32 drwav_result; #define DRWAV_INVALID_FILE -100 #define DRWAV_EOF -101 -#define DRWAV_MAX_SIMD_VECTOR_SIZE 64 // 64 for AVX-512 in the future. +#define DRWAV_MAX_SIMD_VECTOR_SIZE 64 /* 64 for AVX-512 in the future. */ #ifdef _MSC_VER #define DRWAV_INLINE __forceinline #else #ifdef __GNUC__ -#define DRWAV_INLINE inline __attribute__((always_inline)) +#define DRWAV_INLINE __inline__ __attribute__((always_inline)) #else -#define DRWAV_INLINE inline +#define DRWAV_INLINE #endif #endif @@ -902,13 +964,13 @@ typedef drwav_int32 drwav_result; #endif #endif -static const drwav_uint8 drwavGUID_W64_RIFF[16] = {0x72,0x69,0x66,0x66, 0x2E,0x91, 0xCF,0x11, 0xA5,0xD6, 0x28,0xDB,0x04,0xC1,0x00,0x00}; // 66666972-912E-11CF-A5D6-28DB04C10000 -static const drwav_uint8 drwavGUID_W64_WAVE[16] = {0x77,0x61,0x76,0x65, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; // 65766177-ACF3-11D3-8CD1-00C04F8EDB8A -static const drwav_uint8 drwavGUID_W64_JUNK[16] = {0x6A,0x75,0x6E,0x6B, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; // 6B6E756A-ACF3-11D3-8CD1-00C04F8EDB8A -static const drwav_uint8 drwavGUID_W64_FMT [16] = {0x66,0x6D,0x74,0x20, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; // 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A -static const drwav_uint8 drwavGUID_W64_FACT[16] = {0x66,0x61,0x63,0x74, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; // 74636166-ACF3-11D3-8CD1-00C04F8EDB8A -static const drwav_uint8 drwavGUID_W64_DATA[16] = {0x64,0x61,0x74,0x61, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; // 61746164-ACF3-11D3-8CD1-00C04F8EDB8A -static const drwav_uint8 drwavGUID_W64_SMPL[16] = {0x73,0x6D,0x70,0x6C, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; // 6C706D73-ACF3-11D3-8CD1-00C04F8EDB8A +static const drwav_uint8 drwavGUID_W64_RIFF[16] = {0x72,0x69,0x66,0x66, 0x2E,0x91, 0xCF,0x11, 0xA5,0xD6, 0x28,0xDB,0x04,0xC1,0x00,0x00}; /* 66666972-912E-11CF-A5D6-28DB04C10000 */ +static const drwav_uint8 drwavGUID_W64_WAVE[16] = {0x77,0x61,0x76,0x65, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 65766177-ACF3-11D3-8CD1-00C04F8EDB8A */ +static const drwav_uint8 drwavGUID_W64_JUNK[16] = {0x6A,0x75,0x6E,0x6B, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 6B6E756A-ACF3-11D3-8CD1-00C04F8EDB8A */ +static const drwav_uint8 drwavGUID_W64_FMT [16] = {0x66,0x6D,0x74,0x20, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A */ +static const drwav_uint8 drwavGUID_W64_FACT[16] = {0x66,0x61,0x63,0x74, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 74636166-ACF3-11D3-8CD1-00C04F8EDB8A */ +static const drwav_uint8 drwavGUID_W64_DATA[16] = {0x64,0x61,0x74,0x61, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 61746164-ACF3-11D3-8CD1-00C04F8EDB8A */ +static const drwav_uint8 drwavGUID_W64_SMPL[16] = {0x73,0x6D,0x70,0x6C, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 6C706D73-ACF3-11D3-8CD1-00C04F8EDB8A */ static DRWAV_INLINE drwav_bool32 drwav__guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16]) { @@ -963,7 +1025,8 @@ static DRWAV_INLINE drwav_uint64 drwav__bytes_to_u64(const unsigned char* data) static DRWAV_INLINE void drwav__bytes_to_guid(const unsigned char* data, drwav_uint8* guid) { - for (int i = 0; i < 16; ++i) { + int i; + for (i = 0; i < 16; ++i) { guid[i] = data[i]; } } @@ -984,11 +1047,12 @@ drwav* drwav_open_write__internal(const drwav_data_format* pFormat, drwav_uint64 static drwav_result drwav__read_chunk_header(drwav_read_proc onRead, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_chunk_header* pHeaderOut) { if (container == drwav_container_riff) { + unsigned char sizeInBytes[4]; + if (onRead(pUserData, pHeaderOut->id.fourcc, 4) != 4) { return DRWAV_EOF; } - unsigned char sizeInBytes[4]; if (onRead(pUserData, sizeInBytes, 4) != 4) { return DRWAV_INVALID_FILE; } @@ -997,16 +1061,17 @@ static drwav_result drwav__read_chunk_header(drwav_read_proc onRead, void* pUser pHeaderOut->paddingSize = (unsigned int)(pHeaderOut->sizeInBytes % 2); *pRunningBytesReadOut += 8; } else { + unsigned char sizeInBytes[8]; + if (onRead(pUserData, pHeaderOut->id.guid, 16) != 16) { return DRWAV_EOF; } - unsigned char sizeInBytes[8]; if (onRead(pUserData, sizeInBytes, 8) != 8) { return DRWAV_INVALID_FILE; } - pHeaderOut->sizeInBytes = drwav__bytes_to_u64(sizeInBytes) - 24; // <-- Subtract 24 because w64 includes the size of the header. + pHeaderOut->sizeInBytes = drwav__bytes_to_u64(sizeInBytes) - 24; /* <-- Subtract 24 because w64 includes the size of the header. */ pHeaderOut->paddingSize = (unsigned int)(pHeaderOut->sizeInBytes % 8); *pRunningBytesReadOut += 24; } @@ -1040,7 +1105,7 @@ static drwav_bool32 drwav__seek_from_start(drwav_seek_proc onSeek, drwav_uint64 return onSeek(pUserData, (int)offset, drwav_seek_origin_start); } - // Larger than 32-bit seek. + /* Larger than 32-bit seek. */ if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_start)) { return DRWAV_FALSE; } @@ -1057,34 +1122,36 @@ static drwav_bool32 drwav__seek_from_start(drwav_seek_proc onSeek, drwav_uint64 offset -= 0x7FFFFFFF; } - // Should never get here. - //return DRWAV_TRUE; + /* Should never get here. */ + /*return DRWAV_TRUE; */ } static drwav_bool32 drwav__read_fmt(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_fmt* fmtOut) { drwav_chunk_header header; + unsigned char fmt[16]; + if (drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header) != DRWAV_SUCCESS) { return DRWAV_FALSE; } - // Skip non-fmt chunks. + /* Skip non-fmt chunks. */ while ((container == drwav_container_riff && !drwav__fourcc_equal(header.id.fourcc, "fmt ")) || (container == drwav_container_w64 && !drwav__guid_equal(header.id.guid, drwavGUID_W64_FMT))) { if (!drwav__seek_forward(onSeek, header.sizeInBytes + header.paddingSize, pUserData)) { return DRWAV_FALSE; } *pRunningBytesReadOut += header.sizeInBytes + header.paddingSize; - // Try the next header. + /* Try the next header. */ if (drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header) != DRWAV_SUCCESS) { return DRWAV_FALSE; } } - // Validation. + /* Validation. */ if (container == drwav_container_riff) { if (!drwav__fourcc_equal(header.id.fourcc, "fmt ")) { return DRWAV_FALSE; @@ -1096,7 +1163,6 @@ static drwav_bool32 drwav__read_fmt(drwav_read_proc onRead, drwav_seek_proc onSe } - unsigned char fmt[16]; if (onRead(pUserData, fmt, sizeof(fmt)) != sizeof(fmt)) { return DRWAV_FALSE; } @@ -1116,16 +1182,18 @@ static drwav_bool32 drwav__read_fmt(drwav_read_proc onRead, drwav_seek_proc onSe if (header.sizeInBytes > 16) { unsigned char fmt_cbSize[2]; + int bytesReadSoFar = 0; + if (onRead(pUserData, fmt_cbSize, sizeof(fmt_cbSize)) != sizeof(fmt_cbSize)) { - return DRWAV_FALSE; // Expecting more data. + return DRWAV_FALSE; /* Expecting more data. */ } *pRunningBytesReadOut += sizeof(fmt_cbSize); - int bytesReadSoFar = 18; + bytesReadSoFar = 18; fmtOut->extendedSize = drwav__bytes_to_u16(fmt_cbSize); if (fmtOut->extendedSize > 0) { - // Simple validation. + /* Simple validation. */ if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) { if (fmtOut->extendedSize != 22) { return DRWAV_FALSE; @@ -1135,7 +1203,7 @@ static drwav_bool32 drwav__read_fmt(drwav_read_proc onRead, drwav_seek_proc onSe if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) { unsigned char fmtext[22]; if (onRead(pUserData, fmtext, fmtOut->extendedSize) != fmtOut->extendedSize) { - return DRWAV_FALSE; // Expecting more data. + return DRWAV_FALSE; /* Expecting more data. */ } fmtOut->validBitsPerSample = drwav__bytes_to_u16(fmtext + 0); @@ -1151,7 +1219,7 @@ static drwav_bool32 drwav__read_fmt(drwav_read_proc onRead, drwav_seek_proc onSe bytesReadSoFar += fmtOut->extendedSize; } - // Seek past any leftover bytes. For w64 the leftover will be defined based on the chunk size. + /* Seek past any leftover bytes. For w64 the leftover will be defined based on the chunk size. */ if (!onSeek(pUserData, (int)(header.sizeInBytes - bytesReadSoFar), drwav_seek_origin_current)) { return DRWAV_FALSE; } @@ -1245,12 +1313,15 @@ drwav* drwav_open_file(const char* filename) drwav* drwav_open_file_ex(const char* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags) { - FILE* pFile = drwav_fopen(filename, "rb"); + FILE* pFile; + drwav* pWav; + + pFile = drwav_fopen(filename, "rb"); if (pFile == NULL) { return DRWAV_FALSE; } - drwav* pWav = drwav_open_ex(drwav__on_read_stdio, drwav__on_seek_stdio, onChunk, (void*)pFile, pChunkUserData, flags); + pWav = drwav_open_ex(drwav__on_read_stdio, drwav__on_seek_stdio, onChunk, (void*)pFile, pChunkUserData, flags); if (pWav == NULL) { fclose(pFile); return NULL; @@ -1262,12 +1333,15 @@ drwav* drwav_open_file_ex(const char* filename, drwav_chunk_proc onChunk, void* drwav* drwav_open_file_write__internal(const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential) { - FILE* pFile = drwav_fopen(filename, "wb"); + FILE* pFile; + drwav* pWav; + + pFile = drwav_fopen(filename, "wb"); if (pFile == NULL) { return DRWAV_FALSE; } - drwav* pWav = drwav_open_write__internal(pFormat, totalSampleCount, isSequential, drwav__on_write_stdio, drwav__on_seek_stdio, (void*)pFile); + pWav = drwav_open_write__internal(pFormat, totalSampleCount, isSequential, drwav__on_write_stdio, drwav__on_seek_stdio, (void*)pFile); if (pWav == NULL) { fclose(pFile); return NULL; @@ -1285,16 +1359,18 @@ drwav* drwav_open_file_write_sequential(const char* filename, const drwav_data_f { return drwav_open_file_write__internal(filename, pFormat, totalSampleCount, DRWAV_TRUE); } -#endif //DR_WAV_NO_STDIO +#endif /* DR_WAV_NO_STDIO */ static size_t drwav__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead) { drwav__memory_stream* memory = (drwav__memory_stream*)pUserData; + size_t bytesRemaining; + drwav_assert(memory != NULL); drwav_assert(memory->dataSize >= memory->currentReadPos); - size_t bytesRemaining = memory->dataSize - memory->currentReadPos; + bytesRemaining = memory->dataSize - memory->currentReadPos; if (bytesToRead > bytesRemaining) { bytesToRead = bytesRemaining; } @@ -1315,21 +1391,21 @@ static drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_see if (origin == drwav_seek_origin_current) { if (offset > 0) { if (memory->currentReadPos + offset > memory->dataSize) { - return DRWAV_FALSE; // Trying to seek too far forward. + return DRWAV_FALSE; /* Trying to seek too far forward. */ } } else { if (memory->currentReadPos < (size_t)-offset) { - return DRWAV_FALSE; // Trying to seek too far backwards. + return DRWAV_FALSE; /* Trying to seek too far backwards. */ } } - // This will never underflow thanks to the clamps above. + /* This will never underflow thanks to the clamps above. */ memory->currentReadPos += offset; } else { if ((drwav_uint32)offset <= memory->dataSize) { memory->currentReadPos = offset; } else { - return DRWAV_FALSE; // Trying to seek too far forward. + return DRWAV_FALSE; /* Trying to seek too far forward. */ } } @@ -1339,20 +1415,23 @@ static drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_see static size_t drwav__on_write_memory(void* pUserData, const void* pDataIn, size_t bytesToWrite) { drwav__memory_stream_write* memory = (drwav__memory_stream_write*)pUserData; + size_t bytesRemaining; + drwav_assert(memory != NULL); drwav_assert(memory->dataCapacity >= memory->currentWritePos); - size_t bytesRemaining = memory->dataCapacity - memory->currentWritePos; + bytesRemaining = memory->dataCapacity - memory->currentWritePos; if (bytesRemaining < bytesToWrite) { - // Need to reallocate. + /* Need to reallocate. */ + void* pNewData; size_t newDataCapacity = (memory->dataCapacity == 0) ? 256 : memory->dataCapacity * 2; - // If doubling wasn't enough, just make it the minimum required size to write the data. + /* If doubling wasn't enough, just make it the minimum required size to write the data. */ if ((newDataCapacity - memory->currentWritePos) < bytesToWrite) { newDataCapacity = memory->currentWritePos + bytesToWrite; } - void* pNewData = DRWAV_REALLOC(*memory->ppData, newDataCapacity); + pNewData = DRWAV_REALLOC(*memory->ppData, newDataCapacity); if (pNewData == NULL) { return 0; } @@ -1361,8 +1440,7 @@ static size_t drwav__on_write_memory(void* pUserData, const void* pDataIn, size_ memory->dataCapacity = newDataCapacity; } - drwav_uint8* pDataOut = (drwav_uint8*)(*memory->ppData); - DRWAV_COPY_MEMORY(pDataOut + memory->currentWritePos, pDataIn, bytesToWrite); + DRWAV_COPY_MEMORY(((drwav_uint8*)(*memory->ppData)) + memory->currentWritePos, pDataIn, bytesToWrite); memory->currentWritePos += bytesToWrite; if (memory->dataSize < memory->currentWritePos) { @@ -1382,21 +1460,21 @@ static drwav_bool32 drwav__on_seek_memory_write(void* pUserData, int offset, drw if (origin == drwav_seek_origin_current) { if (offset > 0) { if (memory->currentWritePos + offset > memory->dataSize) { - offset = (int)(memory->dataSize - memory->currentWritePos); // Trying to seek too far forward. + offset = (int)(memory->dataSize - memory->currentWritePos); /* Trying to seek too far forward. */ } } else { if (memory->currentWritePos < (size_t)-offset) { - offset = -(int)memory->currentWritePos; // Trying to seek too far backwards. + offset = -(int)memory->currentWritePos; /* Trying to seek too far backwards. */ } } - // This will never underflow thanks to the clamps above. + /* This will never underflow thanks to the clamps above. */ memory->currentWritePos += offset; } else { if ((drwav_uint32)offset <= memory->dataSize) { memory->currentWritePos = offset; } else { - memory->currentWritePos = memory->dataSize; // Trying to seek too far forward. + memory->currentWritePos = memory->dataSize; /* Trying to seek too far forward. */ } } @@ -1410,11 +1488,12 @@ drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize) drwav_bool32 drwav_init_memory_ex(drwav* pWav, const void* data, size_t dataSize, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags) { + drwav__memory_stream memoryStream; + if (data == NULL || dataSize == 0) { return DRWAV_FALSE; } - drwav__memory_stream memoryStream; drwav_zero_memory(&memoryStream, sizeof(memoryStream)); memoryStream.data = (const unsigned char*)data; memoryStream.dataSize = dataSize; @@ -1432,14 +1511,15 @@ drwav_bool32 drwav_init_memory_ex(drwav* pWav, const void* data, size_t dataSize drwav_bool32 drwav_init_memory_write__internal(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential) { + drwav__memory_stream_write memoryStreamWrite; + if (ppData == NULL) { return DRWAV_FALSE; } - *ppData = NULL; // Important because we're using realloc()! + *ppData = NULL; /* Important because we're using realloc()! */ *pDataSize = 0; - drwav__memory_stream_write memoryStreamWrite; drwav_zero_memory(&memoryStreamWrite, sizeof(memoryStreamWrite)); memoryStreamWrite.ppData = ppData; memoryStreamWrite.pDataSize = pDataSize; @@ -1474,17 +1554,19 @@ drwav* drwav_open_memory(const void* data, size_t dataSize) drwav* drwav_open_memory_ex(const void* data, size_t dataSize, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags) { + drwav__memory_stream memoryStream; + drwav* pWav; + if (data == NULL || dataSize == 0) { return NULL; } - drwav__memory_stream memoryStream; drwav_zero_memory(&memoryStream, sizeof(memoryStream)); memoryStream.data = (const unsigned char*)data; memoryStream.dataSize = dataSize; memoryStream.currentReadPos = 0; - drwav* pWav = drwav_open_ex(drwav__on_read_memory, drwav__on_seek_memory, onChunk, (void*)&memoryStream, pChunkUserData, flags); + pWav = drwav_open_ex(drwav__on_read_memory, drwav__on_seek_memory, onChunk, (void*)&memoryStream, pChunkUserData, flags); if (pWav == NULL) { return NULL; } @@ -1497,14 +1579,16 @@ drwav* drwav_open_memory_ex(const void* data, size_t dataSize, drwav_chunk_proc drwav* drwav_open_memory_write__internal(void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential) { + drwav__memory_stream_write memoryStreamWrite; + drwav* pWav; + if (ppData == NULL) { return NULL; } - *ppData = NULL; // Important because we're using realloc()! + *ppData = NULL; /* Important because we're using realloc()! */ *pDataSize = 0; - drwav__memory_stream_write memoryStreamWrite; drwav_zero_memory(&memoryStreamWrite, sizeof(memoryStreamWrite)); memoryStreamWrite.ppData = ppData; memoryStreamWrite.pDataSize = pDataSize; @@ -1512,7 +1596,7 @@ drwav* drwav_open_memory_write__internal(void** ppData, size_t* pDataSize, const memoryStreamWrite.dataCapacity = 0; memoryStreamWrite.currentWritePos = 0; - drwav* pWav = drwav_open_write__internal(pFormat, totalSampleCount, isSequential, drwav__on_write_memory, drwav__on_seek_memory_write, (void*)&memoryStreamWrite); + pWav = drwav_open_write__internal(pFormat, totalSampleCount, isSequential, drwav__on_write_memory, drwav__on_seek_memory_write, (void*)&memoryStreamWrite); if (pWav == NULL) { return NULL; } @@ -1535,10 +1619,12 @@ drwav* drwav_open_memory_write_sequential(void** ppData, size_t* pDataSize, cons size_t drwav__on_read(drwav_read_proc onRead, void* pUserData, void* pBufferOut, size_t bytesToRead, drwav_uint64* pCursor) { + size_t bytesRead; + drwav_assert(onRead != NULL); drwav_assert(pCursor != NULL); - size_t bytesRead = onRead(pUserData, pBufferOut, bytesToRead); + bytesRead = onRead(pUserData, pBufferOut, bytesToRead); *pCursor += bytesRead; return bytesRead; } @@ -1564,8 +1650,10 @@ drwav_bool32 drwav__on_seek(drwav_seek_proc onSeek, void* pUserData, int offset, static drwav_uint32 drwav_get_bytes_per_sample(drwav* pWav) { - // The number of bytes per sample is based on the bits per sample or the block align. We prioritize floor(bitsPerSample/8), but if - // this is zero or the bits per sample is not a multiple of 8 we need to fall back to the block align. + /* + The number of bytes per sample is based on the bits per sample or the block align. We prioritize floor(bitsPerSample/8), but if + this is zero or the bits per sample is not a multiple of 8 we need to fall back to the block align. + */ drwav_uint32 bytesPerSample = pWav->bitsPerSample >> 3; if (bytesPerSample == 0 || (pWav->bitsPerSample & 0x7) != 0) { bytesPerSample = pWav->fmt.blockAlign/pWav->fmt.channels; @@ -1576,8 +1664,10 @@ static drwav_uint32 drwav_get_bytes_per_sample(drwav* pWav) static drwav_uint32 drwav_get_bytes_per_pcm_frame(drwav* pWav) { - // The number of bytes per frame is based on the bits per sample or the block align. We prioritize floor(bitsPerSample*channels/8), but if - // this is zero or the bits per frame is not a multiple of 8 we need to fall back to the block align. + /* + The number of bytes per frame is based on the bits per sample or the block align. We prioritize floor(bitsPerSample*channels/8), but if + this is zero or the bits per frame is not a multiple of 8 we need to fall back to the block align. + */ drwav_uint32 bitsPerFrame = pWav->bitsPerSample * pWav->fmt.channels; drwav_uint32 bytesPerFrame = bitsPerFrame >> 3; if (bytesPerFrame == 0 || (bitsPerFrame & 0x7) != 0) { @@ -1595,79 +1685,93 @@ drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onS drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, drwav_uint32 flags) { + drwav_uint64 cursor; /* <-- Keeps track of the byte position so we can seek to specific locations. */ + drwav_bool32 sequential; + unsigned char riff[4]; + drwav_fmt fmt; + unsigned short translatedFormatTag; + drwav_uint64 sampleCountFromFactChunk; + drwav_bool32 foundDataChunk; + drwav_uint64 dataChunkSize; + drwav_uint64 chunkSize; + if (onRead == NULL || onSeek == NULL) { return DRWAV_FALSE; } - drwav_uint64 cursor = 0; // <-- Keeps track of the byte position so we can seek to specific locations. - drwav_bool32 sequential = (flags & DRWAV_SEQUENTIAL) != 0; + cursor = 0; + sequential = (flags & DRWAV_SEQUENTIAL) != 0; drwav_zero_memory(pWav, sizeof(*pWav)); pWav->onRead = onRead; pWav->onSeek = onSeek; pWav->pUserData = pReadSeekUserData; - // The first 4 bytes should be the RIFF identifier. - unsigned char riff[4]; + /* The first 4 bytes should be the RIFF identifier. */ if (drwav__on_read(onRead, pReadSeekUserData, riff, sizeof(riff), &cursor) != sizeof(riff)) { return DRWAV_FALSE; } - // The first 4 bytes can be used to identify the container. For RIFF files it will start with "RIFF" and for - // w64 it will start with "riff". + /* + The first 4 bytes can be used to identify the container. For RIFF files it will start with "RIFF" and for + w64 it will start with "riff". + */ if (drwav__fourcc_equal(riff, "RIFF")) { pWav->container = drwav_container_riff; } else if (drwav__fourcc_equal(riff, "riff")) { + int i; + drwav_uint8 riff2[12]; + pWav->container = drwav_container_w64; - // Check the rest of the GUID for validity. - drwav_uint8 riff2[12]; + /* Check the rest of the GUID for validity. */ if (drwav__on_read(onRead, pReadSeekUserData, riff2, sizeof(riff2), &cursor) != sizeof(riff2)) { return DRWAV_FALSE; } - for (int i = 0; i < 12; ++i) { + for (i = 0; i < 12; ++i) { if (riff2[i] != drwavGUID_W64_RIFF[i+4]) { return DRWAV_FALSE; } } } else { - return DRWAV_FALSE; // Unknown or unsupported container. + return DRWAV_FALSE; /* Unknown or unsupported container. */ } if (pWav->container == drwav_container_riff) { - // RIFF/WAVE unsigned char chunkSizeBytes[4]; + unsigned char wave[4]; + + /* RIFF/WAVE */ if (drwav__on_read(onRead, pReadSeekUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) { return DRWAV_FALSE; } - unsigned int chunkSize = drwav__bytes_to_u32(chunkSizeBytes); - if (chunkSize < 36) { - return DRWAV_FALSE; // Chunk size should always be at least 36 bytes. + if (drwav__bytes_to_u32(chunkSizeBytes) < 36) { + return DRWAV_FALSE; /* Chunk size should always be at least 36 bytes. */ } - unsigned char wave[4]; if (drwav__on_read(onRead, pReadSeekUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) { return DRWAV_FALSE; } if (!drwav__fourcc_equal(wave, "WAVE")) { - return DRWAV_FALSE; // Expecting "WAVE". + return DRWAV_FALSE; /* Expecting "WAVE". */ } } else { - // W64 - unsigned char chunkSize[8]; - if (drwav__on_read(onRead, pReadSeekUserData, chunkSize, sizeof(chunkSize), &cursor) != sizeof(chunkSize)) { - return DRWAV_FALSE; - } - - if (drwav__bytes_to_u64(chunkSize) < 80) { - return DRWAV_FALSE; - } - + unsigned char chunkSizeBytes[8]; drwav_uint8 wave[16]; + + /* W64 */ + if (drwav__on_read(onRead, pReadSeekUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) { + return DRWAV_FALSE; + } + + if (drwav__bytes_to_u64(chunkSizeBytes) < 80) { + return DRWAV_FALSE; + } + if (drwav__on_read(onRead, pReadSeekUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) { return DRWAV_FALSE; } @@ -1678,38 +1782,39 @@ drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc } - // The next bytes should be the "fmt " chunk. - drwav_fmt fmt; + /* The next bytes should be the "fmt " chunk. */ if (!drwav__read_fmt(onRead, onSeek, pReadSeekUserData, pWav->container, &cursor, &fmt)) { - return DRWAV_FALSE; // Failed to read the "fmt " chunk. + return DRWAV_FALSE; /* Failed to read the "fmt " chunk. */ } - // Basic validation. + /* Basic validation. */ if (fmt.sampleRate == 0 || fmt.channels == 0 || fmt.bitsPerSample == 0 || fmt.blockAlign == 0) { - return DRWAV_FALSE; // Invalid channel count. Probably an invalid WAV file. + return DRWAV_FALSE; /* Invalid channel count. Probably an invalid WAV file. */ } - // Translate the internal format. - unsigned short translatedFormatTag = fmt.formatTag; + /* Translate the internal format. */ + translatedFormatTag = fmt.formatTag; if (translatedFormatTag == DR_WAVE_FORMAT_EXTENSIBLE) { translatedFormatTag = drwav__bytes_to_u16(fmt.subFormat + 0); } - drwav_uint64 sampleCountFromFactChunk = 0; + sampleCountFromFactChunk = 0; - // We need to enumerate over each chunk for two reasons: - // 1) The "data" chunk may not be the next one - // 2) We may want to report each chunk back to the client - // - // In order to correctly report each chunk back to the client we will need to keep looping until the end of the file. - drwav_bool32 foundDataChunk = DRWAV_FALSE; - drwav_uint64 dataChunkSize = 0; + /* + We need to enumerate over each chunk for two reasons: + 1) The "data" chunk may not be the next one + 2) We may want to report each chunk back to the client + + In order to correctly report each chunk back to the client we will need to keep looping until the end of the file. + */ + foundDataChunk = DRWAV_FALSE; + dataChunkSize = 0; - // The next chunk we care about is the "data" chunk. This is not necessarily the next chunk so we'll need to loop. - drwav_uint64 chunkSize = 0; + /* The next chunk we care about is the "data" chunk. This is not necessarily the next chunk so we'll need to loop. */ + chunkSize = 0; for (;;) { drwav_chunk_header header; @@ -1718,16 +1823,18 @@ drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc if (!foundDataChunk) { return DRWAV_FALSE; } else { - break; // Probably at the end of the file. Get out of the loop. + break; /* Probably at the end of the file. Get out of the loop. */ } } - // Tell the client about this chunk. + /* Tell the client about this chunk. */ if (!sequential && onChunk != NULL) { drwav_uint64 callbackBytesRead = onChunk(pChunkUserData, onRead, onSeek, pReadSeekUserData, &header); - // dr_wav may need to read the contents of the chunk, so we now need to seek back to the position before - // we called the callback. + /* + dr_wav may need to read the contents of the chunk, so we now need to seek back to the position before + we called the callback. + */ if (callbackBytesRead > 0) { if (!drwav__seek_from_start(onSeek, cursor, pReadSeekUserData)) { return DRWAV_FALSE; @@ -1753,13 +1860,15 @@ drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc } } - // If at this point we have found the data chunk and we're running in sequential mode, we need to break out of this loop. The reason for - // this is that we would otherwise require a backwards seek which sequential mode forbids. + /* + If at this point we have found the data chunk and we're running in sequential mode, we need to break out of this loop. The reason for + this is that we would otherwise require a backwards seek which sequential mode forbids. + */ if (foundDataChunk && sequential) { break; } - // Optional. Get the total sample count from the FACT chunk. This is useful for compressed formats. + /* Optional. Get the total sample count from the FACT chunk. This is useful for compressed formats. */ if (pWav->container == drwav_container_riff) { if (drwav__fourcc_equal(header.id.fourcc, "fact")) { drwav_uint32 sampleCount; @@ -1772,8 +1881,10 @@ drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc pWav->dataChunkDataPos = cursor; } - // The sample count in the "fact" chunk is either unreliable, or I'm not understanding it properly. For now I am only enabling this - // for Microsoft ADPCM formats. + /* + The sample count in the "fact" chunk is either unreliable, or I'm not understanding it properly. For now I am only enabling this + for Microsoft ADPCM formats. + */ if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { sampleCountFromFactChunk = sampleCount; } else { @@ -1793,15 +1904,17 @@ drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc } } - // "smpl" chunk. + /* "smpl" chunk. */ if (pWav->container == drwav_container_riff) { if (drwav__fourcc_equal(header.id.fourcc, "smpl")) { - unsigned char smplHeaderData[36]; // 36 = size of the smpl header section, not including the loop data. + unsigned char smplHeaderData[36]; /* 36 = size of the smpl header section, not including the loop data. */ if (chunkSize >= sizeof(smplHeaderData)) { drwav_uint64 bytesJustRead = drwav__on_read(onRead, pReadSeekUserData, smplHeaderData, sizeof(smplHeaderData), &cursor); chunkSize -= bytesJustRead; if (bytesJustRead == sizeof(smplHeaderData)) { + drwav_uint32 iLoop; + pWav->smpl.manufacturer = drwav__bytes_to_u32(smplHeaderData+0); pWav->smpl.product = drwav__bytes_to_u32(smplHeaderData+4); pWav->smpl.samplePeriod = drwav__bytes_to_u32(smplHeaderData+8); @@ -1812,8 +1925,8 @@ drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc pWav->smpl.numSampleLoops = drwav__bytes_to_u32(smplHeaderData+28); pWav->smpl.samplerData = drwav__bytes_to_u32(smplHeaderData+32); - for (drwav_uint32 iLoop = 0; iLoop < pWav->smpl.numSampleLoops && iLoop < drwav_countof(pWav->smpl.loops); ++iLoop) { - unsigned char smplLoopData[24]; // 24 = size of a loop section in the smpl chunk. + for (iLoop = 0; iLoop < pWav->smpl.numSampleLoops && iLoop < drwav_countof(pWav->smpl.loops); ++iLoop) { + unsigned char smplLoopData[24]; /* 24 = size of a loop section in the smpl chunk. */ bytesJustRead = drwav__on_read(onRead, pReadSeekUserData, smplLoopData, sizeof(smplLoopData), &cursor); chunkSize -= bytesJustRead; @@ -1825,22 +1938,24 @@ drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc pWav->smpl.loops[iLoop].fraction = drwav__bytes_to_u32(smplLoopData+16); pWav->smpl.loops[iLoop].playCount = drwav__bytes_to_u32(smplLoopData+20); } else { - break; // Break from the smpl loop for loop. + break; /* Break from the smpl loop for loop. */ } } } } else { - // Looks like invalid data. Ignore the chunk. + /* Looks like invalid data. Ignore the chunk. */ } } } else { if (drwav__guid_equal(header.id.guid, drwavGUID_W64_SMPL)) { - // This path will be hit when a W64 WAV file contains a smpl chunk. I don't have a sample file to test this path, so a contribution - // is welcome to add support for this. + /* + This path will be hit when a W64 WAV file contains a smpl chunk. I don't have a sample file to test this path, so a contribution + is welcome to add support for this. + */ } } - // Make sure we seek past the padding. + /* Make sure we seek past the padding. */ chunkSize += header.paddingSize; if (!drwav__seek_forward(onSeek, chunkSize, pReadSeekUserData)) { break; @@ -1852,12 +1967,12 @@ drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc } } - // If we haven't found a data chunk, return an error. + /* If we haven't found a data chunk, return an error. */ if (!foundDataChunk) { return DRWAV_FALSE; } - // We may have moved passed the data chunk. If so we need to move back. If running in sequential mode we can assume we are already sitting on the data chunk. + /* We may have moved passed the data chunk. If so we need to move back. If running in sequential mode we can assume we are already sitting on the data chunk. */ if (!sequential) { if (!drwav__seek_from_start(onSeek, pWav->dataChunkDataPos, pReadSeekUserData)) { return DRWAV_FALSE; @@ -1866,7 +1981,7 @@ drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc } - // At this point we should be sitting on the first byte of the raw audio data. + /* At this point we should be sitting on the first byte of the raw audio data. */ pWav->fmt = fmt; pWav->sampleRate = fmt.sampleRate; @@ -1883,7 +1998,7 @@ drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; - pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (6*pWav->channels))) * 2)) / fmt.channels; // x2 because two samples per byte. + pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (6*pWav->channels))) * 2)) / fmt.channels; /* x2 because two samples per byte. */ } if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; @@ -1891,7 +2006,7 @@ drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc } } - // Some formats only support a certain number of channels. + /* Some formats only support a certain number of channels. */ if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { if (pWav->channels > 2) { return DRWAV_FALSE; @@ -1899,15 +2014,17 @@ drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc } #ifdef DR_WAV_LIBSNDFILE_COMPAT - // I use libsndfile as a benchmark for testing, however in the version I'm using (from the Windows installer on the libsndfile website), - // it appears the total sample count libsndfile uses for MS-ADPCM is incorrect. It would seem they are computing the total sample count - // from the number of blocks, however this results in the inclusion of extra silent samples at the end of the last block. The correct - // way to know the total sample count is to inspect the "fact" chunk, which should always be present for compressed formats, and should - // always include the sample count. This little block of code below is only used to emulate the libsndfile logic so I can properly run my - // correctness tests against libsndfile, and is disabled by default. + /* + I use libsndfile as a benchmark for testing, however in the version I'm using (from the Windows installer on the libsndfile website), + it appears the total sample count libsndfile uses for MS-ADPCM is incorrect. It would seem they are computing the total sample count + from the number of blocks, however this results in the inclusion of extra silent samples at the end of the last block. The correct + way to know the total sample count is to inspect the "fact" chunk, which should always be present for compressed formats, and should + always include the sample count. This little block of code below is only used to emulate the libsndfile logic so I can properly run my + correctness tests against libsndfile, and is disabled by default. + */ if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; - pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (6*pWav->channels))) * 2)) / fmt.channels; // x2 because two samples per byte. + pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (6*pWav->channels))) * 2)) / fmt.channels; /* x2 because two samples per byte. */ } if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; @@ -1941,17 +2058,21 @@ drwav_uint32 drwav_data_chunk_size_riff(drwav_uint64 dataChunkSize) drwav_uint64 drwav_riff_chunk_size_w64(drwav_uint64 dataChunkSize) { - return 80 + 24 + dataChunkSize; // +24 because W64 includes the size of the GUID and size fields. + return 80 + 24 + dataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */ } drwav_uint64 drwav_data_chunk_size_w64(drwav_uint64 dataChunkSize) { - return 24 + dataChunkSize; // +24 because W64 includes the size of the GUID and size fields. + return 24 + dataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */ } drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData) { + size_t runningPos = 0; + drwav_uint64 initialDataChunkSize = 0; + drwav_uint64 chunkSizeFMT; + if (pWav == NULL) { return DRWAV_FALSE; } @@ -1961,11 +2082,11 @@ drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pF } if (!isSequential && onSeek == NULL) { - return DRWAV_FALSE; // <-- onSeek is required when in non-sequential mode. + return DRWAV_FALSE; /* <-- onSeek is required when in non-sequential mode. */ } - // Not currently supporting compressed formats. Will need to add support for the "fact" chunk before we enable this. + /* Not currently supporting compressed formats. Will need to add support for the "fact" chunk before we enable this. */ if (pFormat->format == DR_WAVE_FORMAT_EXTENSIBLE) { return DRWAV_FALSE; } @@ -1987,21 +2108,21 @@ drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pF pWav->fmt.extendedSize = 0; pWav->isSequentialWrite = isSequential; - - size_t runningPos = 0; - - // The initial values for the "RIFF" and "data" chunks depends on whether or not we are initializing in sequential mode or not. In - // sequential mode we set this to its final values straight away since they can be calculated from the total sample count. In non- - // sequential mode we initialize it all to zero and fill it out in drwav_uninit() using a backwards seek. - drwav_uint64 initialDataChunkSize = 0; + /* + The initial values for the "RIFF" and "data" chunks depends on whether or not we are initializing in sequential mode or not. In + sequential mode we set this to its final values straight away since they can be calculated from the total sample count. In non- + sequential mode we initialize it all to zero and fill it out in drwav_uninit() using a backwards seek. + */ if (isSequential) { initialDataChunkSize = (totalSampleCount * pWav->fmt.bitsPerSample) / 8; - // The RIFF container has a limit on the number of samples. drwav is not allowing this. There's no practical limits for Wave64 - // so for the sake of simplicity I'm not doing any validation for that. + /* + The RIFF container has a limit on the number of samples. drwav is not allowing this. There's no practical limits for Wave64 + so for the sake of simplicity I'm not doing any validation for that. + */ if (pFormat->container == drwav_container_riff) { if (initialDataChunkSize > (0xFFFFFFFF - 36)) { - return DRWAV_FALSE; // Not enough room to store every sample. + return DRWAV_FALSE; /* Not enough room to store every sample. */ } } } @@ -2009,21 +2130,20 @@ drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pF pWav->dataChunkDataSizeTargetWrite = initialDataChunkSize; - // "RIFF" chunk. + /* "RIFF" chunk. */ if (pFormat->container == drwav_container_riff) { - drwav_uint32 chunkSizeRIFF = 36 + (drwav_uint32)initialDataChunkSize; // +36 = "RIFF"+[RIFF Chunk Size]+"WAVE" + [sizeof "fmt " chunk] + drwav_uint32 chunkSizeRIFF = 36 + (drwav_uint32)initialDataChunkSize; /* +36 = "RIFF"+[RIFF Chunk Size]+"WAVE" + [sizeof "fmt " chunk] */ runningPos += pWav->onWrite(pUserData, "RIFF", 4); runningPos += pWav->onWrite(pUserData, &chunkSizeRIFF, 4); runningPos += pWav->onWrite(pUserData, "WAVE", 4); } else { - drwav_uint64 chunkSizeRIFF = 80 + 24 + initialDataChunkSize; // +24 because W64 includes the size of the GUID and size fields. + drwav_uint64 chunkSizeRIFF = 80 + 24 + initialDataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */ runningPos += pWav->onWrite(pUserData, drwavGUID_W64_RIFF, 16); runningPos += pWav->onWrite(pUserData, &chunkSizeRIFF, 8); runningPos += pWav->onWrite(pUserData, drwavGUID_W64_WAVE, 16); } - // "fmt " chunk. - drwav_uint64 chunkSizeFMT; + /* "fmt " chunk. */ if (pFormat->container == drwav_container_riff) { chunkSizeFMT = 16; runningPos += pWav->onWrite(pUserData, "fmt ", 4); @@ -2043,19 +2163,19 @@ drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pF pWav->dataChunkDataPos = runningPos; - // "data" chunk. + /* "data" chunk. */ if (pFormat->container == drwav_container_riff) { drwav_uint32 chunkSizeDATA = (drwav_uint32)initialDataChunkSize; runningPos += pWav->onWrite(pUserData, "data", 4); runningPos += pWav->onWrite(pUserData, &chunkSizeDATA, 4); } else { - drwav_uint64 chunkSizeDATA = 24 + initialDataChunkSize; // +24 because W64 includes the size of the GUID and size fields. + drwav_uint64 chunkSizeDATA = 24 + initialDataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */ runningPos += pWav->onWrite(pUserData, drwavGUID_W64_DATA, 16); runningPos += pWav->onWrite(pUserData, &chunkSizeDATA, 8); } - // Simple validation. + /* Simple validation. */ if (pFormat->container == drwav_container_riff) { if (runningPos != 20 + chunkSizeFMT + 8) { return DRWAV_FALSE; @@ -2068,7 +2188,7 @@ drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pF - // Set some properties for the client's convenience. + /* Set some properties for the client's convenience. */ pWav->container = pFormat->container; pWav->channels = (drwav_uint16)pFormat->channels; pWav->sampleRate = pFormat->sampleRate; @@ -2081,12 +2201,12 @@ drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pF drwav_bool32 drwav_init_write(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData) { - return drwav_init_write__internal(pWav, pFormat, 0, DRWAV_FALSE, onWrite, onSeek, pUserData); // DRWAV_FALSE = Not Sequential + return drwav_init_write__internal(pWav, pFormat, 0, DRWAV_FALSE, onWrite, onSeek, pUserData); /* DRWAV_FALSE = Not Sequential */ } drwav_bool32 drwav_init_write_sequential(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_write_proc onWrite, void* pUserData) { - return drwav_init_write__internal(pWav, pFormat, totalSampleCount, DRWAV_TRUE, onWrite, NULL, pUserData); // DRWAV_TRUE = Sequential + return drwav_init_write__internal(pWav, pFormat, totalSampleCount, DRWAV_TRUE, onWrite, NULL, pUserData); /* DRWAV_TRUE = Sequential */ } void drwav_uninit(drwav* pWav) @@ -2095,17 +2215,20 @@ void drwav_uninit(drwav* pWav) return; } - // If the drwav object was opened in write mode we'll need to finalize a few things: - // - Make sure the "data" chunk is aligned to 16-bits for RIFF containers, or 64 bits for W64 containers. - // - Set the size of the "data" chunk. + /* + If the drwav object was opened in write mode we'll need to finalize a few things: + - Make sure the "data" chunk is aligned to 16-bits for RIFF containers, or 64 bits for W64 containers. + - Set the size of the "data" chunk. + */ if (pWav->onWrite != NULL) { - // Validation for sequential mode. + drwav_uint32 paddingSize = 0; + + /* Validation for sequential mode. */ if (pWav->isSequentialWrite) { drwav_assert(pWav->dataChunkDataSize == pWav->dataChunkDataSizeTargetWrite); } - // Padding. Do not adjust pWav->dataChunkDataSize - this should not include the padding. - drwav_uint32 paddingSize = 0; + /* Padding. Do not adjust pWav->dataChunkDataSize - this should not include the padding. */ if (pWav->container == drwav_container_riff) { paddingSize = (drwav_uint32)(pWav->dataChunkDataSize % 2); } else { @@ -2117,30 +2240,31 @@ void drwav_uninit(drwav* pWav) pWav->onWrite(pWav->pUserData, &paddingData, paddingSize); } - - // Chunk sizes. When using sequential mode, these will have been filled in at initialization time. We only need - // to do this when using non-sequential mode. + /* + Chunk sizes. When using sequential mode, these will have been filled in at initialization time. We only need + to do this when using non-sequential mode. + */ if (pWav->onSeek && !pWav->isSequentialWrite) { if (pWav->container == drwav_container_riff) { - // The "RIFF" chunk size. + /* The "RIFF" chunk size. */ if (pWav->onSeek(pWav->pUserData, 4, drwav_seek_origin_start)) { drwav_uint32 riffChunkSize = drwav_riff_chunk_size_riff(pWav->dataChunkDataSize); pWav->onWrite(pWav->pUserData, &riffChunkSize, 4); } - // the "data" chunk size. + /* the "data" chunk size. */ if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos + 4, drwav_seek_origin_start)) { drwav_uint32 dataChunkSize = drwav_data_chunk_size_riff(pWav->dataChunkDataSize); pWav->onWrite(pWav->pUserData, &dataChunkSize, 4); } } else { - // The "RIFF" chunk size. + /* The "RIFF" chunk size. */ if (pWav->onSeek(pWav->pUserData, 16, drwav_seek_origin_start)) { drwav_uint64 riffChunkSize = drwav_riff_chunk_size_w64(pWav->dataChunkDataSize); pWav->onWrite(pWav->pUserData, &riffChunkSize, 8); } - // The "data" chunk size. + /* The "data" chunk size. */ if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos + 16, drwav_seek_origin_start)) { drwav_uint64 dataChunkSize = drwav_data_chunk_size_w64(pWav->dataChunkDataSize); pWav->onWrite(pWav->pUserData, &dataChunkSize, 8); @@ -2150,8 +2274,10 @@ void drwav_uninit(drwav* pWav) } #ifndef DR_WAV_NO_STDIO - // If we opened the file with drwav_open_file() we will want to close the file handle. We can know whether or not drwav_open_file() - // was used by looking at the onRead and onSeek callbacks. + /* + If we opened the file with drwav_open_file() we will want to close the file handle. We can know whether or not drwav_open_file() + was used by looking at the onRead and onSeek callbacks. + */ if (pWav->onRead == drwav__on_read_stdio || pWav->onWrite == drwav__on_write_stdio) { fclose((FILE*)pWav->pUserData); } @@ -2214,6 +2340,8 @@ void drwav_close(drwav* pWav) size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut) { + size_t bytesRead; + if (pWav == NULL || bytesToRead == 0 || pBufferOut == NULL) { return 0; } @@ -2222,7 +2350,7 @@ size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut) bytesToRead = (size_t)pWav->bytesRemaining; } - size_t bytesRead = pWav->onRead(pWav->pUserData, pBufferOut, bytesToRead); + bytesRead = pWav->onRead(pWav->pUserData, pBufferOut, bytesToRead); pWav->bytesRemaining -= bytesRead; return bytesRead; @@ -2230,58 +2358,64 @@ size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut) drwav_uint64 drwav_read(drwav* pWav, drwav_uint64 samplesToRead, void* pBufferOut) { + drwav_uint32 bytesPerSample; + size_t bytesRead; + if (pWav == NULL || samplesToRead == 0 || pBufferOut == NULL) { return 0; } - // Cannot use this function for compressed formats. + /* Cannot use this function for compressed formats. */ if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { return 0; } - drwav_uint32 bytesPerSample = drwav_get_bytes_per_sample(pWav); + bytesPerSample = drwav_get_bytes_per_sample(pWav); if (bytesPerSample == 0) { return 0; } - // Don't try to read more samples than can potentially fit in the output buffer. + /* Don't try to read more samples than can potentially fit in the output buffer. */ if (samplesToRead * bytesPerSample > DRWAV_SIZE_MAX) { samplesToRead = DRWAV_SIZE_MAX / bytesPerSample; } - size_t bytesRead = drwav_read_raw(pWav, (size_t)(samplesToRead * bytesPerSample), pBufferOut); + bytesRead = drwav_read_raw(pWav, (size_t)(samplesToRead * bytesPerSample), pBufferOut); return bytesRead / bytesPerSample; } drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut) { + drwav_uint32 bytesPerFrame; + size_t bytesRead; + if (pWav == NULL || framesToRead == 0 || pBufferOut == NULL) { return 0; } - // Cannot use this function for compressed formats. + /* Cannot use this function for compressed formats. */ if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { return 0; } - drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); if (bytesPerFrame == 0) { return 0; } - // Don't try to read more samples than can potentially fit in the output buffer. + /* Don't try to read more samples than can potentially fit in the output buffer. */ if (framesToRead * bytesPerFrame > DRWAV_SIZE_MAX) { framesToRead = DRWAV_SIZE_MAX / bytesPerFrame; } - size_t bytesRead = drwav_read_raw(pWav, (size_t)(framesToRead * bytesPerFrame), pBufferOut); + bytesRead = drwav_read_raw(pWav, (size_t)(framesToRead * bytesPerFrame), pBufferOut); return bytesRead / bytesPerFrame; } drwav_bool32 drwav_seek_to_first_pcm_frame(drwav* pWav) { if (pWav->onWrite != NULL) { - return DRWAV_FALSE; // No seeking in write mode. + return DRWAV_FALSE; /* No seeking in write mode. */ } if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, drwav_seek_origin_start)) { @@ -2298,34 +2432,37 @@ drwav_bool32 drwav_seek_to_first_pcm_frame(drwav* pWav) drwav_bool32 drwav_seek_to_sample(drwav* pWav, drwav_uint64 sample) { - // Seeking should be compatible with wave files > 2GB. + /* Seeking should be compatible with wave files > 2GB. */ if (pWav->onWrite != NULL) { - return DRWAV_FALSE; // No seeking in write mode. + return DRWAV_FALSE; /* No seeking in write mode. */ } if (pWav == NULL || pWav->onSeek == NULL) { return DRWAV_FALSE; } - // If there are no samples, just return DRWAV_TRUE without doing anything. + /* If there are no samples, just return DRWAV_TRUE without doing anything. */ if (pWav->totalSampleCount == 0) { return DRWAV_TRUE; } - // Make sure the sample is clamped. + /* Make sure the sample is clamped. */ if (sample >= pWav->totalSampleCount) { sample = pWav->totalSampleCount - 1; } - - // For compressed formats we just use a slow generic seek. If we are seeking forward we just seek forward. If we are going backwards we need - // to seek back to the start. + /* + For compressed formats we just use a slow generic seek. If we are seeking forward we just seek forward. If we are going backwards we need + to seek back to the start. + */ if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { - // TODO: This can be optimized. + /* TODO: This can be optimized. */ - // If we're seeking forward it's simple - just keep reading samples until we hit the sample we're requesting. If we're seeking backwards, - // we first need to seek back to the start and then just do the same thing as a forward seek. + /* + If we're seeking forward it's simple - just keep reading samples until we hit the sample we're requesting. If we're seeking backwards, + we first need to seek back to the start and then just do the same thing as a forward seek. + */ if (sample < pWav->compressed.iCurrentSample) { if (!drwav_seek_to_first_pcm_frame(pWav)) { return DRWAV_FALSE; @@ -2337,18 +2474,18 @@ drwav_bool32 drwav_seek_to_sample(drwav* pWav, drwav_uint64 sample) drwav_int16 devnull[2048]; while (offset > 0) { + drwav_uint64 samplesRead = 0; drwav_uint64 samplesToRead = offset; if (samplesToRead > 2048) { samplesToRead = 2048; } - drwav_uint64 samplesRead = 0; if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { samplesRead = drwav_read_s16__msadpcm(pWav, samplesToRead, devnull); } else if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { samplesRead = drwav_read_s16__ima(pWav, samplesToRead, devnull); } else { - assert(DRWAV_FALSE); // If this assertion is triggered it means I've implemented a new compressed format but forgot to add a branch for it here. + assert(DRWAV_FALSE); /* If this assertion is triggered it means I've implemented a new compressed format but forgot to add a branch for it here. */ } if (samplesRead != samplesToRead) { @@ -2359,18 +2496,22 @@ drwav_bool32 drwav_seek_to_sample(drwav* pWav, drwav_uint64 sample) } } } else { - drwav_uint64 totalSizeInBytes = pWav->totalPCMFrameCount * drwav_get_bytes_per_pcm_frame(pWav); + drwav_uint64 totalSizeInBytes; + drwav_uint64 currentBytePos; + drwav_uint64 targetBytePos; + drwav_uint64 offset; + + totalSizeInBytes = pWav->totalPCMFrameCount * drwav_get_bytes_per_pcm_frame(pWav); drwav_assert(totalSizeInBytes >= pWav->bytesRemaining); - drwav_uint64 currentBytePos = totalSizeInBytes - pWav->bytesRemaining; - drwav_uint64 targetBytePos = sample * drwav_get_bytes_per_sample(pWav); + currentBytePos = totalSizeInBytes - pWav->bytesRemaining; + targetBytePos = sample * drwav_get_bytes_per_sample(pWav); - drwav_uint64 offset; if (currentBytePos < targetBytePos) { - // Offset forwards. + /* Offset forwards. */ offset = (targetBytePos - currentBytePos); } else { - // Offset backwards. + /* Offset backwards. */ if (!drwav_seek_to_first_pcm_frame(pWav)) { return DRWAV_FALSE; } @@ -2399,11 +2540,13 @@ drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex) size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData) { + size_t bytesWritten; + if (pWav == NULL || bytesToWrite == 0 || pData == NULL) { return 0; } - size_t bytesWritten = pWav->onWrite(pWav->pUserData, pData, bytesToWrite); + bytesWritten = pWav->onWrite(pWav->pUserData, pData, bytesToWrite); pWav->dataChunkDataSize += bytesWritten; return bytesWritten; @@ -2411,24 +2554,29 @@ size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData) drwav_uint64 drwav_write(drwav* pWav, drwav_uint64 samplesToWrite, const void* pData) { + drwav_uint64 bytesToWrite; + drwav_uint64 bytesWritten; + const drwav_uint8* pRunningData; + if (pWav == NULL || samplesToWrite == 0 || pData == NULL) { return 0; } - drwav_uint64 bytesToWrite = ((samplesToWrite * pWav->bitsPerSample) / 8); + bytesToWrite = ((samplesToWrite * pWav->bitsPerSample) / 8); if (bytesToWrite > DRWAV_SIZE_MAX) { return 0; } - drwav_uint64 bytesWritten = 0; - const drwav_uint8* pRunningData = (const drwav_uint8*)pData; + bytesWritten = 0; + pRunningData = (const drwav_uint8*)pData; while (bytesToWrite > 0) { + size_t bytesJustWritten; drwav_uint64 bytesToWriteThisIteration = bytesToWrite; if (bytesToWriteThisIteration > DRWAV_SIZE_MAX) { bytesToWriteThisIteration = DRWAV_SIZE_MAX; } - size_t bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, pRunningData); + bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, pRunningData); if (bytesJustWritten == 0) { break; } @@ -2450,19 +2598,19 @@ drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, con drwav_uint64 drwav_read_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut) { + drwav_uint64 totalSamplesRead = 0; + drwav_assert(pWav != NULL); drwav_assert(samplesToRead > 0); drwav_assert(pBufferOut != NULL); - // TODO: Lots of room for optimization here. - - drwav_uint64 totalSamplesRead = 0; + /* TODO: Lots of room for optimization here. */ while (samplesToRead > 0 && pWav->compressed.iCurrentSample < pWav->totalSampleCount) { - // If there are no cached samples we need to load a new block. + /* If there are no cached samples we need to load a new block. */ if (pWav->msadpcm.cachedSampleCount == 0 && pWav->msadpcm.bytesRemainingInBlock == 0) { if (pWav->channels == 1) { - // Mono. + /* Mono. */ drwav_uint8 header[7]; if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { return totalSamplesRead; @@ -2477,7 +2625,7 @@ drwav_uint64 drwav_read_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, dr pWav->msadpcm.cachedSamples[3] = pWav->msadpcm.prevSamples[0][1]; pWav->msadpcm.cachedSampleCount = 2; } else { - // Stereo. + /* Stereo. */ drwav_uint8 header[14]; if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { return totalSamplesRead; @@ -2501,7 +2649,7 @@ drwav_uint64 drwav_read_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, dr } } - // Output anything that's cached. + /* Output anything that's cached. */ while (samplesToRead > 0 && pWav->msadpcm.cachedSampleCount > 0 && pWav->compressed.iCurrentSample < pWav->totalSampleCount) { pBufferOut[0] = (drwav_int16)pWav->msadpcm.cachedSamples[drwav_countof(pWav->msadpcm.cachedSamples) - pWav->msadpcm.cachedSampleCount]; pWav->msadpcm.cachedSampleCount -= 1; @@ -2517,22 +2665,14 @@ drwav_uint64 drwav_read_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, dr } - // If there's nothing left in the cache, just go ahead and load more. If there's nothing left to load in the current block we just continue to the next - // loop iteration which will trigger the loading of a new block. + /* + If there's nothing left in the cache, just go ahead and load more. If there's nothing left to load in the current block we just continue to the next + loop iteration which will trigger the loading of a new block. + */ if (pWav->msadpcm.cachedSampleCount == 0) { if (pWav->msadpcm.bytesRemainingInBlock == 0) { continue; } else { - drwav_uint8 nibbles; - if (pWav->onRead(pWav->pUserData, &nibbles, 1) != 1) { - return totalSamplesRead; - } - pWav->msadpcm.bytesRemainingInBlock -= 1; - - // TODO: Optimize away these if statements. - drwav_int32 nibble0 = ((nibbles & 0xF0) >> 4); if ((nibbles & 0x80)) { nibble0 |= 0xFFFFFFF0UL; } - drwav_int32 nibble1 = ((nibbles & 0x0F) >> 0); if ((nibbles & 0x08)) { nibble1 |= 0xFFFFFFF0UL; } - static drwav_int32 adaptationTable[] = { 230, 230, 230, 230, 307, 409, 512, 614, 768, 614, 512, 409, 307, 230, 230, 230 @@ -2540,9 +2680,24 @@ drwav_uint64 drwav_read_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, dr static drwav_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 }; static drwav_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 }; + drwav_uint8 nibbles; + drwav_int32 nibble0; + drwav_int32 nibble1; + + if (pWav->onRead(pWav->pUserData, &nibbles, 1) != 1) { + return totalSamplesRead; + } + pWav->msadpcm.bytesRemainingInBlock -= 1; + + /* TODO: Optimize away these if statements. */ + nibble0 = ((nibbles & 0xF0) >> 4); if ((nibbles & 0x80)) { nibble0 |= 0xFFFFFFF0UL; } + nibble1 = ((nibbles & 0x0F) >> 0); if ((nibbles & 0x08)) { nibble1 |= 0xFFFFFFF0UL; } + if (pWav->channels == 1) { - // Mono. + /* Mono. */ drwav_int32 newSample0; + drwav_int32 newSample1; + newSample0 = ((pWav->msadpcm.prevSamples[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevSamples[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8; newSample0 += nibble0 * pWav->msadpcm.delta[0]; newSample0 = drwav_clamp(newSample0, -32768, 32767); @@ -2556,7 +2711,6 @@ drwav_uint64 drwav_read_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, dr pWav->msadpcm.prevSamples[0][1] = newSample0; - drwav_int32 newSample1; newSample1 = ((pWav->msadpcm.prevSamples[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevSamples[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8; newSample1 += nibble1 * pWav->msadpcm.delta[0]; newSample1 = drwav_clamp(newSample1, -32768, 32767); @@ -2574,10 +2728,11 @@ drwav_uint64 drwav_read_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, dr pWav->msadpcm.cachedSamples[3] = newSample1; pWav->msadpcm.cachedSampleCount = 2; } else { - // Stereo. - - // Left. + /* Stereo. */ drwav_int32 newSample0; + drwav_int32 newSample1; + + /* Left. */ newSample0 = ((pWav->msadpcm.prevSamples[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevSamples[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8; newSample0 += nibble0 * pWav->msadpcm.delta[0]; newSample0 = drwav_clamp(newSample0, -32768, 32767); @@ -2591,8 +2746,7 @@ drwav_uint64 drwav_read_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, dr pWav->msadpcm.prevSamples[0][1] = newSample0; - // Right. - drwav_int32 newSample1; + /* Right. */ newSample1 = ((pWav->msadpcm.prevSamples[1][1] * coeff1Table[pWav->msadpcm.predictor[1]]) + (pWav->msadpcm.prevSamples[1][0] * coeff2Table[pWav->msadpcm.predictor[1]])) >> 8; newSample1 += nibble1 * pWav->msadpcm.delta[1]; newSample1 = drwav_clamp(newSample1, -32768, 32767); @@ -2618,19 +2772,19 @@ drwav_uint64 drwav_read_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, dr drwav_uint64 drwav_read_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut) { + drwav_uint64 totalSamplesRead = 0; + drwav_assert(pWav != NULL); drwav_assert(samplesToRead > 0); drwav_assert(pBufferOut != NULL); - // TODO: Lots of room for optimization here. - - drwav_uint64 totalSamplesRead = 0; + /* TODO: Lots of room for optimization here. */ while (samplesToRead > 0 && pWav->compressed.iCurrentSample < pWav->totalSampleCount) { - // If there are no cached samples we need to load a new block. + /* If there are no cached samples we need to load a new block. */ if (pWav->ima.cachedSampleCount == 0 && pWav->ima.bytesRemainingInBlock == 0) { if (pWav->channels == 1) { - // Mono. + /* Mono. */ drwav_uint8 header[4]; if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { return totalSamplesRead; @@ -2642,7 +2796,7 @@ drwav_uint64 drwav_read_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_ pWav->ima.cachedSamples[drwav_countof(pWav->ima.cachedSamples) - 1] = pWav->ima.predictor[0]; pWav->ima.cachedSampleCount = 1; } else { - // Stereo. + /* Stereo. */ drwav_uint8 header[8]; if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { return totalSamplesRead; @@ -2660,7 +2814,7 @@ drwav_uint64 drwav_read_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_ } } - // Output anything that's cached. + /* Output anything that's cached. */ while (samplesToRead > 0 && pWav->ima.cachedSampleCount > 0 && pWav->compressed.iCurrentSample < pWav->totalSampleCount) { pBufferOut[0] = (drwav_int16)pWav->ima.cachedSamples[drwav_countof(pWav->ima.cachedSamples) - pWav->ima.cachedSampleCount]; pWav->ima.cachedSampleCount -= 1; @@ -2675,8 +2829,10 @@ drwav_uint64 drwav_read_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_ return totalSamplesRead; } - // If there's nothing left in the cache, just go ahead and load more. If there's nothing left to load in the current block we just continue to the next - // loop iteration which will trigger the loading of a new block. + /* + If there's nothing left in the cache, just go ahead and load more. If there's nothing left to load in the current block we just continue to the next + loop iteration which will trigger the loading of a new block. + */ if (pWav->ima.cachedSampleCount == 0) { if (pWav->ima.bytesRemainingInBlock == 0) { continue; @@ -2698,17 +2854,22 @@ drwav_uint64 drwav_read_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_ 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 }; - // From what I can tell with stereo streams, it looks like every 4 bytes (8 samples) is for one channel. So it goes 4 bytes for the - // left channel, 4 bytes for the right channel. + drwav_uint32 iChannel; + + /* + From what I can tell with stereo streams, it looks like every 4 bytes (8 samples) is for one channel. So it goes 4 bytes for the + left channel, 4 bytes for the right channel. + */ pWav->ima.cachedSampleCount = 8 * pWav->channels; - for (drwav_uint32 iChannel = 0; iChannel < pWav->channels; ++iChannel) { + for (iChannel = 0; iChannel < pWav->channels; ++iChannel) { + drwav_uint32 iByte; drwav_uint8 nibbles[4]; if (pWav->onRead(pWav->pUserData, &nibbles, 4) != 4) { return totalSamplesRead; } pWav->ima.bytesRemainingInBlock -= 4; - for (drwav_uint32 iByte = 0; iByte < 4; ++iByte) { + for (iByte = 0; iByte < 4; ++iByte) { drwav_uint8 nibble0 = ((nibbles[iByte] & 0x0F) >> 0); drwav_uint8 nibble1 = ((nibbles[iByte] & 0xF0) >> 4); @@ -2803,16 +2964,18 @@ static DRWAV_INLINE drwav_int16 drwav__mulaw_to_s16(drwav_uint8 sampleIn) static void drwav__pcm_to_s16(drwav_int16* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned int bytesPerSample) { - // Special case for 8-bit sample data because it's treated as unsigned. + unsigned int i; + + /* Special case for 8-bit sample data because it's treated as unsigned. */ if (bytesPerSample == 1) { drwav_u8_to_s16(pOut, pIn, totalSampleCount); return; } - // Slightly more optimal implementation for common formats. + /* Slightly more optimal implementation for common formats. */ if (bytesPerSample == 2) { - for (unsigned int i = 0; i < totalSampleCount; ++i) { + for (i = 0; i < totalSampleCount; ++i) { *pOut++ = ((const drwav_int16*)pIn)[i]; } return; @@ -2827,15 +2990,15 @@ static void drwav__pcm_to_s16(drwav_int16* pOut, const unsigned char* pIn, size_ } - // Anything more than 64 bits per sample is not supported. + /* Anything more than 64 bits per sample is not supported. */ if (bytesPerSample > 8) { drwav_zero_memory(pOut, totalSampleCount * sizeof(*pOut)); return; } - // Generic, slow converter. - for (unsigned int i = 0; i < totalSampleCount; ++i) { + /* Generic, slow converter. */ + for (i = 0; i < totalSampleCount; ++i) { drwav_uint64 sample = 0; unsigned int shift = (8 - bytesPerSample) * 8; @@ -2859,7 +3022,7 @@ static void drwav__ieee_to_s16(drwav_int16* pOut, const unsigned char* pIn, size drwav_f64_to_s16(pOut, (const double*)pIn, totalSampleCount); return; } else { - // Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. + /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */ drwav_zero_memory(pOut, totalSampleCount * sizeof(*pOut)); return; } @@ -2868,8 +3031,10 @@ static void drwav__ieee_to_s16(drwav_int16* pOut, const unsigned char* pIn, size drwav_uint64 drwav_read_s16__pcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut) { drwav_uint32 bytesPerSample; + drwav_uint64 totalSamplesRead; + unsigned char sampleData[4096]; - // Fast path. + /* Fast path. */ if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 16) { return drwav_read(pWav, samplesToRead, pBufferOut); } @@ -2879,8 +3044,8 @@ drwav_uint64 drwav_read_s16__pcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_ return 0; } - drwav_uint64 totalSamplesRead = 0; - unsigned char sampleData[4096]; + totalSamplesRead = 0; + while (samplesToRead > 0) { drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/bytesPerSample), sampleData); if (samplesRead == 0) { @@ -2899,13 +3064,16 @@ drwav_uint64 drwav_read_s16__pcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_ drwav_uint64 drwav_read_s16__ieee(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut) { + drwav_uint64 totalSamplesRead; + unsigned char sampleData[4096]; + drwav_uint32 bytesPerSample = drwav_get_bytes_per_sample(pWav); if (bytesPerSample == 0) { return 0; } - drwav_uint64 totalSamplesRead = 0; - unsigned char sampleData[4096]; + totalSamplesRead = 0; + while (samplesToRead > 0) { drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/bytesPerSample), sampleData); if (samplesRead == 0) { @@ -2924,13 +3092,16 @@ drwav_uint64 drwav_read_s16__ieee(drwav* pWav, drwav_uint64 samplesToRead, drwav drwav_uint64 drwav_read_s16__alaw(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut) { + drwav_uint64 totalSamplesRead; + unsigned char sampleData[4096]; + drwav_uint32 bytesPerSample = drwav_get_bytes_per_sample(pWav); if (bytesPerSample == 0) { return 0; } - drwav_uint64 totalSamplesRead = 0; - unsigned char sampleData[4096]; + totalSamplesRead = 0; + while (samplesToRead > 0) { drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/bytesPerSample), sampleData); if (samplesRead == 0) { @@ -2949,13 +3120,16 @@ drwav_uint64 drwav_read_s16__alaw(drwav* pWav, drwav_uint64 samplesToRead, drwav drwav_uint64 drwav_read_s16__mulaw(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut) { + drwav_uint64 totalSamplesRead; + unsigned char sampleData[4096]; + drwav_uint32 bytesPerSample = drwav_get_bytes_per_sample(pWav); if (bytesPerSample == 0) { return 0; } - drwav_uint64 totalSamplesRead = 0; - unsigned char sampleData[4096]; + totalSamplesRead = 0; + while (samplesToRead > 0) { drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/bytesPerSample), sampleData); if (samplesRead == 0) { @@ -2978,7 +3152,7 @@ drwav_uint64 drwav_read_s16(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16 return 0; } - // Don't try to read more samples than can potentially fit in the output buffer. + /* Don't try to read more samples than can potentially fit in the output buffer. */ if (samplesToRead * sizeof(drwav_int16) > DRWAV_SIZE_MAX) { samplesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int16); } @@ -3018,7 +3192,8 @@ drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, d void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) { int r; - for (size_t i = 0; i < sampleCount; ++i) { + size_t i; + for (i = 0; i < sampleCount; ++i) { int x = pIn[i]; r = x - 128; r = r << 8; @@ -3029,7 +3204,8 @@ void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCou void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) { int r; - for (size_t i = 0; i < sampleCount; ++i) { + size_t i; + for (i = 0; i < sampleCount; ++i) { int x = ((int)(((unsigned int)(((const unsigned char*)pIn)[i*3+0]) << 8) | ((unsigned int)(((const unsigned char*)pIn)[i*3+1]) << 16) | ((unsigned int)(((const unsigned char*)pIn)[i*3+2])) << 24)) >> 8; r = x >> 8; pOut[i] = (short)r; @@ -3039,7 +3215,8 @@ void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCo void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount) { int r; - for (size_t i = 0; i < sampleCount; ++i) { + size_t i; + for (i = 0; i < sampleCount; ++i) { int x = pIn[i]; r = x >> 16; pOut[i] = (short)r; @@ -3049,7 +3226,8 @@ void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCo void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount) { int r; - for (size_t i = 0; i < sampleCount; ++i) { + size_t i; + for (i = 0; i < sampleCount; ++i) { float x = pIn[i]; float c; c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); @@ -3063,7 +3241,8 @@ void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount) void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount) { int r; - for (size_t i = 0; i < sampleCount; ++i) { + size_t i; + for (i = 0; i < sampleCount; ++i) { double x = pIn[i]; double c; c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); @@ -3076,14 +3255,16 @@ void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount) void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) { - for (size_t i = 0; i < sampleCount; ++i) { + size_t i; + for (i = 0; i < sampleCount; ++i) { pOut[i] = drwav__alaw_to_s16(pIn[i]); } } void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) { - for (size_t i = 0; i < sampleCount; ++i) { + size_t i; + for (i = 0; i < sampleCount; ++i) { pOut[i] = drwav__mulaw_to_s16(pIn[i]); } } @@ -3092,13 +3273,15 @@ void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sample static void drwav__pcm_to_f32(float* pOut, const unsigned char* pIn, size_t sampleCount, unsigned int bytesPerSample) { - // Special case for 8-bit sample data because it's treated as unsigned. + unsigned int i; + + /* Special case for 8-bit sample data because it's treated as unsigned. */ if (bytesPerSample == 1) { drwav_u8_to_f32(pOut, pIn, sampleCount); return; } - // Slightly more optimal implementation for common formats. + /* Slightly more optimal implementation for common formats. */ if (bytesPerSample == 2) { drwav_s16_to_f32(pOut, (const drwav_int16*)pIn, sampleCount); return; @@ -3113,15 +3296,15 @@ static void drwav__pcm_to_f32(float* pOut, const unsigned char* pIn, size_t samp } - // Anything more than 64 bits per sample is not supported. + /* Anything more than 64 bits per sample is not supported. */ if (bytesPerSample > 8) { drwav_zero_memory(pOut, sampleCount * sizeof(*pOut)); return; } - // Generic, slow converter. - for (unsigned int i = 0; i < sampleCount; ++i) { + /* Generic, slow converter. */ + for (i = 0; i < sampleCount; ++i) { drwav_uint64 sample = 0; unsigned int shift = (8 - bytesPerSample) * 8; @@ -3139,7 +3322,8 @@ static void drwav__pcm_to_f32(float* pOut, const unsigned char* pIn, size_t samp static void drwav__ieee_to_f32(float* pOut, const unsigned char* pIn, size_t sampleCount, unsigned int bytesPerSample) { if (bytesPerSample == 4) { - for (unsigned int i = 0; i < sampleCount; ++i) { + unsigned int i; + for (i = 0; i < sampleCount; ++i) { *pOut++ = ((const float*)pIn)[i]; } return; @@ -3147,7 +3331,7 @@ static void drwav__ieee_to_f32(float* pOut, const unsigned char* pIn, size_t sam drwav_f64_to_f32(pOut, (const double*)pIn, sampleCount); return; } else { - // Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. + /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */ drwav_zero_memory(pOut, sampleCount * sizeof(*pOut)); return; } @@ -3156,13 +3340,16 @@ static void drwav__ieee_to_f32(float* pOut, const unsigned char* pIn, size_t sam drwav_uint64 drwav_read_f32__pcm(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut) { + drwav_uint64 totalSamplesRead; + unsigned char sampleData[4096]; + drwav_uint32 bytesPerSample = drwav_get_bytes_per_sample(pWav); if (bytesPerSample == 0) { return 0; } - drwav_uint64 totalSamplesRead = 0; - unsigned char sampleData[4096]; + totalSamplesRead = 0; + while (samplesToRead > 0) { drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/bytesPerSample), sampleData); if (samplesRead == 0) { @@ -3181,8 +3368,10 @@ drwav_uint64 drwav_read_f32__pcm(drwav* pWav, drwav_uint64 samplesToRead, float* drwav_uint64 drwav_read_f32__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut) { - // We're just going to borrow the implementation from the drwav_read_s16() since ADPCM is a little bit more complicated than other formats and I don't - // want to duplicate that code. + /* + We're just going to borrow the implementation from the drwav_read_s16() since ADPCM is a little bit more complicated than other formats and I don't + want to duplicate that code. + */ drwav_uint64 totalSamplesRead = 0; drwav_int16 samples16[2048]; while (samplesToRead > 0) { @@ -3191,7 +3380,7 @@ drwav_uint64 drwav_read_f32__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, fl break; } - drwav_s16_to_f32(pBufferOut, samples16, (size_t)samplesRead); // <-- Safe cast because we're clamping to 2048. + drwav_s16_to_f32(pBufferOut, samples16, (size_t)samplesRead); /* <-- Safe cast because we're clamping to 2048. */ pBufferOut += samplesRead; samplesToRead -= samplesRead; @@ -3203,8 +3392,10 @@ drwav_uint64 drwav_read_f32__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, fl drwav_uint64 drwav_read_f32__ima(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut) { - // We're just going to borrow the implementation from the drwav_read_s16() since IMA-ADPCM is a little bit more complicated than other formats and I don't - // want to duplicate that code. + /* + We're just going to borrow the implementation from the drwav_read_s16() since IMA-ADPCM is a little bit more complicated than other formats and I don't + want to duplicate that code. + */ drwav_uint64 totalSamplesRead = 0; drwav_int16 samples16[2048]; while (samplesToRead > 0) { @@ -3213,7 +3404,7 @@ drwav_uint64 drwav_read_f32__ima(drwav* pWav, drwav_uint64 samplesToRead, float* break; } - drwav_s16_to_f32(pBufferOut, samples16, (size_t)samplesRead); // <-- Safe cast because we're clamping to 2048. + drwav_s16_to_f32(pBufferOut, samples16, (size_t)samplesRead); /* <-- Safe cast because we're clamping to 2048. */ pBufferOut += samplesRead; samplesToRead -= samplesRead; @@ -3225,9 +3416,11 @@ drwav_uint64 drwav_read_f32__ima(drwav* pWav, drwav_uint64 samplesToRead, float* drwav_uint64 drwav_read_f32__ieee(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut) { + drwav_uint64 totalSamplesRead; + unsigned char sampleData[4096]; drwav_uint32 bytesPerSample; - // Fast path. + /* Fast path. */ if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT && pWav->bitsPerSample == 32) { return drwav_read(pWav, samplesToRead, pBufferOut); } @@ -3237,8 +3430,8 @@ drwav_uint64 drwav_read_f32__ieee(drwav* pWav, drwav_uint64 samplesToRead, float return 0; } - drwav_uint64 totalSamplesRead = 0; - unsigned char sampleData[4096]; + totalSamplesRead = 0; + while (samplesToRead > 0) { drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/bytesPerSample), sampleData); if (samplesRead == 0) { @@ -3257,13 +3450,15 @@ drwav_uint64 drwav_read_f32__ieee(drwav* pWav, drwav_uint64 samplesToRead, float drwav_uint64 drwav_read_f32__alaw(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut) { + drwav_uint64 totalSamplesRead; + unsigned char sampleData[4096]; drwav_uint32 bytesPerSample = drwav_get_bytes_per_sample(pWav); if (bytesPerSample == 0) { return 0; } - drwav_uint64 totalSamplesRead = 0; - unsigned char sampleData[4096]; + totalSamplesRead = 0; + while (samplesToRead > 0) { drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/bytesPerSample), sampleData); if (samplesRead == 0) { @@ -3282,13 +3477,16 @@ drwav_uint64 drwav_read_f32__alaw(drwav* pWav, drwav_uint64 samplesToRead, float drwav_uint64 drwav_read_f32__mulaw(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut) { + drwav_uint64 totalSamplesRead; + unsigned char sampleData[4096]; + drwav_uint32 bytesPerSample = drwav_get_bytes_per_sample(pWav); if (bytesPerSample == 0) { return 0; } - drwav_uint64 totalSamplesRead = 0; - unsigned char sampleData[4096]; + totalSamplesRead = 0; + while (samplesToRead > 0) { drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/bytesPerSample), sampleData); if (samplesRead == 0) { @@ -3311,7 +3509,7 @@ drwav_uint64 drwav_read_f32(drwav* pWav, drwav_uint64 samplesToRead, float* pBuf return 0; } - // Don't try to read more samples than can potentially fit in the output buffer. + /* Don't try to read more samples than can potentially fit in the output buffer. */ if (samplesToRead * sizeof(float) > DRWAV_SIZE_MAX) { samplesToRead = DRWAV_SIZE_MAX / sizeof(float); } @@ -3350,20 +3548,24 @@ drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, f void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) { + size_t i; + if (pOut == NULL || pIn == NULL) { return; } #ifdef DR_WAV_LIBSNDFILE_COMPAT - // It appears libsndfile uses slightly different logic for the u8 -> f32 conversion to dr_wav, which in my opinion is incorrect. It appears - // libsndfile performs the conversion something like "f32 = (u8 / 256) * 2 - 1", however I think it should be "f32 = (u8 / 255) * 2 - 1" (note - // the divisor of 256 vs 255). I use libsndfile as a benchmark for testing, so I'm therefore leaving this block here just for my automated - // correctness testing. This is disabled by default. - for (size_t i = 0; i < sampleCount; ++i) { + /* + It appears libsndfile uses slightly different logic for the u8 -> f32 conversion to dr_wav, which in my opinion is incorrect. It appears + libsndfile performs the conversion something like "f32 = (u8 / 256) * 2 - 1", however I think it should be "f32 = (u8 / 255) * 2 - 1" (note + the divisor of 256 vs 255). I use libsndfile as a benchmark for testing, so I'm therefore leaving this block here just for my automated + correctness testing. This is disabled by default. + */ + for (i = 0; i < sampleCount; ++i) { *pOut++ = (pIn[i] / 256.0f) * 2 - 1; } #else - for (size_t i = 0; i < sampleCount; ++i) { + for (i = 0; i < sampleCount; ++i) { *pOut++ = (pIn[i] / 255.0f) * 2 - 1; } #endif @@ -3371,22 +3573,26 @@ void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount) { + size_t i; + if (pOut == NULL || pIn == NULL) { return; } - for (size_t i = 0; i < sampleCount; ++i) { + for (i = 0; i < sampleCount; ++i) { *pOut++ = pIn[i] / 32768.0f; } } void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) { + size_t i; + if (pOut == NULL || pIn == NULL) { return; } - for (size_t i = 0; i < sampleCount; ++i) { + for (i = 0; i < sampleCount; ++i) { unsigned int s0 = pIn[i*3 + 0]; unsigned int s1 = pIn[i*3 + 1]; unsigned int s2 = pIn[i*3 + 2]; @@ -3398,44 +3604,51 @@ void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount) { + size_t i; if (pOut == NULL || pIn == NULL) { return; } - for (size_t i = 0; i < sampleCount; ++i) { + for (i = 0; i < sampleCount; ++i) { *pOut++ = (float)(pIn[i] / 2147483648.0); } } void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount) { + size_t i; + if (pOut == NULL || pIn == NULL) { return; } - for (size_t i = 0; i < sampleCount; ++i) { + for (i = 0; i < sampleCount; ++i) { *pOut++ = (float)pIn[i]; } } void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) { + size_t i; + if (pOut == NULL || pIn == NULL) { return; } - for (size_t i = 0; i < sampleCount; ++i) { + for (i = 0; i < sampleCount; ++i) { *pOut++ = drwav__alaw_to_s16(pIn[i]) / 32768.0f; } } void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) { + size_t i; + if (pOut == NULL || pIn == NULL) { return; } - for (size_t i = 0; i < sampleCount; ++i) { + for (i = 0; i < sampleCount; ++i) { *pOut++ = drwav__mulaw_to_s16(pIn[i]) / 32768.0f; } } @@ -3444,13 +3657,15 @@ void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) static void drwav__pcm_to_s32(drwav_int32* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned int bytesPerSample) { - // Special case for 8-bit sample data because it's treated as unsigned. + unsigned int i; + + /* Special case for 8-bit sample data because it's treated as unsigned. */ if (bytesPerSample == 1) { drwav_u8_to_s32(pOut, pIn, totalSampleCount); return; } - // Slightly more optimal implementation for common formats. + /* Slightly more optimal implementation for common formats. */ if (bytesPerSample == 2) { drwav_s16_to_s32(pOut, (const drwav_int16*)pIn, totalSampleCount); return; @@ -3460,22 +3675,22 @@ static void drwav__pcm_to_s32(drwav_int32* pOut, const unsigned char* pIn, size_ return; } if (bytesPerSample == 4) { - for (unsigned int i = 0; i < totalSampleCount; ++i) { + for (i = 0; i < totalSampleCount; ++i) { *pOut++ = ((const drwav_int32*)pIn)[i]; } return; } - // Anything more than 64 bits per sample is not supported. + /* Anything more than 64 bits per sample is not supported. */ if (bytesPerSample > 8) { drwav_zero_memory(pOut, totalSampleCount * sizeof(*pOut)); return; } - // Generic, slow converter. - for (unsigned int i = 0; i < totalSampleCount; ++i) { + /* Generic, slow converter. */ + for (i = 0; i < totalSampleCount; ++i) { drwav_uint64 sample = 0; unsigned int shift = (8 - bytesPerSample) * 8; @@ -3499,7 +3714,7 @@ static void drwav__ieee_to_s32(drwav_int32* pOut, const unsigned char* pIn, size drwav_f64_to_s32(pOut, (const double*)pIn, totalSampleCount); return; } else { - // Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. + /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */ drwav_zero_memory(pOut, totalSampleCount * sizeof(*pOut)); return; } @@ -3508,9 +3723,11 @@ static void drwav__ieee_to_s32(drwav_int32* pOut, const unsigned char* pIn, size drwav_uint64 drwav_read_s32__pcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut) { + drwav_uint64 totalSamplesRead; + unsigned char sampleData[4096]; drwav_uint32 bytesPerSample; - // Fast path. + /* Fast path. */ if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 32) { return drwav_read(pWav, samplesToRead, pBufferOut); } @@ -3520,8 +3737,8 @@ drwav_uint64 drwav_read_s32__pcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_ return 0; } - drwav_uint64 totalSamplesRead = 0; - unsigned char sampleData[4096]; + totalSamplesRead = 0; + while (samplesToRead > 0) { drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/bytesPerSample), sampleData); if (samplesRead == 0) { @@ -3540,8 +3757,10 @@ drwav_uint64 drwav_read_s32__pcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_ drwav_uint64 drwav_read_s32__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut) { - // We're just going to borrow the implementation from the drwav_read_s16() since ADPCM is a little bit more complicated than other formats and I don't - // want to duplicate that code. + /* + We're just going to borrow the implementation from the drwav_read_s16() since ADPCM is a little bit more complicated than other formats and I don't + want to duplicate that code. + */ drwav_uint64 totalSamplesRead = 0; drwav_int16 samples16[2048]; while (samplesToRead > 0) { @@ -3550,7 +3769,7 @@ drwav_uint64 drwav_read_s32__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, dr break; } - drwav_s16_to_s32(pBufferOut, samples16, (size_t)samplesRead); // <-- Safe cast because we're clamping to 2048. + drwav_s16_to_s32(pBufferOut, samples16, (size_t)samplesRead); /* <-- Safe cast because we're clamping to 2048. */ pBufferOut += samplesRead; samplesToRead -= samplesRead; @@ -3562,8 +3781,10 @@ drwav_uint64 drwav_read_s32__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, dr drwav_uint64 drwav_read_s32__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut) { - // We're just going to borrow the implementation from the drwav_read_s16() since IMA-ADPCM is a little bit more complicated than other formats and I don't - // want to duplicate that code. + /* + We're just going to borrow the implementation from the drwav_read_s16() since IMA-ADPCM is a little bit more complicated than other formats and I don't + want to duplicate that code. + */ drwav_uint64 totalSamplesRead = 0; drwav_int16 samples16[2048]; while (samplesToRead > 0) { @@ -3572,7 +3793,7 @@ drwav_uint64 drwav_read_s32__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_ break; } - drwav_s16_to_s32(pBufferOut, samples16, (size_t)samplesRead); // <-- Safe cast because we're clamping to 2048. + drwav_s16_to_s32(pBufferOut, samples16, (size_t)samplesRead); /* <-- Safe cast because we're clamping to 2048. */ pBufferOut += samplesRead; samplesToRead -= samplesRead; @@ -3584,13 +3805,16 @@ drwav_uint64 drwav_read_s32__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_ drwav_uint64 drwav_read_s32__ieee(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut) { + drwav_uint64 totalSamplesRead; + unsigned char sampleData[4096]; + drwav_uint32 bytesPerSample = drwav_get_bytes_per_sample(pWav); if (bytesPerSample == 0) { return 0; } - drwav_uint64 totalSamplesRead = 0; - unsigned char sampleData[4096]; + totalSamplesRead = 0; + while (samplesToRead > 0) { drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/bytesPerSample), sampleData); if (samplesRead == 0) { @@ -3609,13 +3833,16 @@ drwav_uint64 drwav_read_s32__ieee(drwav* pWav, drwav_uint64 samplesToRead, drwav drwav_uint64 drwav_read_s32__alaw(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut) { + drwav_uint64 totalSamplesRead; + unsigned char sampleData[4096]; + drwav_uint32 bytesPerSample = drwav_get_bytes_per_sample(pWav); if (bytesPerSample == 0) { return 0; } - drwav_uint64 totalSamplesRead = 0; - unsigned char sampleData[4096]; + totalSamplesRead = 0; + while (samplesToRead > 0) { drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/bytesPerSample), sampleData); if (samplesRead == 0) { @@ -3634,13 +3861,16 @@ drwav_uint64 drwav_read_s32__alaw(drwav* pWav, drwav_uint64 samplesToRead, drwav drwav_uint64 drwav_read_s32__mulaw(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut) { + drwav_uint64 totalSamplesRead; + unsigned char sampleData[4096]; + drwav_uint32 bytesPerSample = drwav_get_bytes_per_sample(pWav); if (bytesPerSample == 0) { return 0; } - drwav_uint64 totalSamplesRead = 0; - unsigned char sampleData[4096]; + totalSamplesRead = 0; + while (samplesToRead > 0) { drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/bytesPerSample), sampleData); if (samplesRead == 0) { @@ -3663,7 +3893,7 @@ drwav_uint64 drwav_read_s32(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32 return 0; } - // Don't try to read more samples than can potentially fit in the output buffer. + /* Don't try to read more samples than can potentially fit in the output buffer. */ if (samplesToRead * sizeof(drwav_int32) > DRWAV_SIZE_MAX) { samplesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int32); } @@ -3703,33 +3933,39 @@ drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, d void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) { + size_t i; + if (pOut == NULL || pIn == NULL) { return; } - for (size_t i = 0; i < sampleCount; ++i) { + for (i = 0; i < sampleCount; ++i) { *pOut++ = ((int)pIn[i] - 128) << 24; } } void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount) { + size_t i; + if (pOut == NULL || pIn == NULL) { return; } - for (size_t i = 0; i < sampleCount; ++i) { + for (i = 0; i < sampleCount; ++i) { *pOut++ = pIn[i] << 16; } } void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) { + size_t i; + if (pOut == NULL || pIn == NULL) { return; } - for (size_t i = 0; i < sampleCount; ++i) { + for (i = 0; i < sampleCount; ++i) { unsigned int s0 = pIn[i*3 + 0]; unsigned int s1 = pIn[i*3 + 1]; unsigned int s2 = pIn[i*3 + 2]; @@ -3741,44 +3977,52 @@ void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCo void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount) { + size_t i; + if (pOut == NULL || pIn == NULL) { return; } - for (size_t i = 0; i < sampleCount; ++i) { + for (i = 0; i < sampleCount; ++i) { *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]); } } void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount) { + size_t i; + if (pOut == NULL || pIn == NULL) { return; } - for (size_t i = 0; i < sampleCount; ++i) { + for (i = 0; i < sampleCount; ++i) { *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]); } } void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) { + size_t i; + if (pOut == NULL || pIn == NULL) { return; } - for (size_t i = 0; i < sampleCount; ++i) { + for (i = 0; i < sampleCount; ++i) { *pOut++ = ((drwav_int32)drwav__alaw_to_s16(pIn[i])) << 16; } } void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) { + size_t i; + if (pOut == NULL || pIn == NULL) { return; } - for (size_t i= 0; i < sampleCount; ++i) { + for (i= 0; i < sampleCount; ++i) { *pOut++ = ((drwav_int32)drwav__mulaw_to_s16(pIn[i])) << 16; } } @@ -3787,105 +4031,145 @@ void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sample drwav_int16* drwav__read_and_close_s16(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) { + drwav_uint64 sampleDataSize; + drwav_int16* pSampleData; + drwav_uint64 samplesRead; + drwav_assert(pWav != NULL); - drwav_uint64 sampleDataSize = pWav->totalSampleCount * sizeof(drwav_int16); + sampleDataSize = pWav->totalSampleCount * sizeof(drwav_int16); if (sampleDataSize > DRWAV_SIZE_MAX) { drwav_uninit(pWav); - return NULL; // File's too big. + return NULL; /* File's too big. */ } - drwav_int16* pSampleData = (drwav_int16*)DRWAV_MALLOC((size_t)sampleDataSize); // <-- Safe cast due to the check above. + pSampleData = (drwav_int16*)DRWAV_MALLOC((size_t)sampleDataSize); /* <-- Safe cast due to the check above. */ if (pSampleData == NULL) { drwav_uninit(pWav); - return NULL; // Failed to allocate memory. + return NULL; /* Failed to allocate memory. */ } - drwav_uint64 samplesRead = drwav_read_s16(pWav, (size_t)pWav->totalSampleCount, pSampleData); + samplesRead = drwav_read_s16(pWav, (size_t)pWav->totalSampleCount, pSampleData); if (samplesRead != pWav->totalSampleCount) { DRWAV_FREE(pSampleData); drwav_uninit(pWav); - return NULL; // There was an error reading the samples. + return NULL; /* There was an error reading the samples. */ } drwav_uninit(pWav); - if (sampleRate) *sampleRate = pWav->sampleRate; - if (channels) *channels = pWav->channels; - if (totalSampleCount) *totalSampleCount = pWav->totalSampleCount; + if (sampleRate) { + *sampleRate = pWav->sampleRate; + } + if (channels) { + *channels = pWav->channels; + } + if (totalSampleCount) { + *totalSampleCount = pWav->totalSampleCount; + } + return pSampleData; } float* drwav__read_and_close_f32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) { + drwav_uint64 sampleDataSize; + float* pSampleData; + drwav_uint64 samplesRead; + drwav_assert(pWav != NULL); - drwav_uint64 sampleDataSize = pWav->totalSampleCount * sizeof(float); + sampleDataSize = pWav->totalSampleCount * sizeof(float); if (sampleDataSize > DRWAV_SIZE_MAX) { drwav_uninit(pWav); - return NULL; // File's too big. + return NULL; /* File's too big. */ } - float* pSampleData = (float*)DRWAV_MALLOC((size_t)sampleDataSize); // <-- Safe cast due to the check above. + pSampleData = (float*)DRWAV_MALLOC((size_t)sampleDataSize); /* <-- Safe cast due to the check above. */ if (pSampleData == NULL) { drwav_uninit(pWav); - return NULL; // Failed to allocate memory. + return NULL; /* Failed to allocate memory. */ } - drwav_uint64 samplesRead = drwav_read_f32(pWav, (size_t)pWav->totalSampleCount, pSampleData); + samplesRead = drwav_read_f32(pWav, (size_t)pWav->totalSampleCount, pSampleData); if (samplesRead != pWav->totalSampleCount) { DRWAV_FREE(pSampleData); drwav_uninit(pWav); - return NULL; // There was an error reading the samples. + return NULL; /* There was an error reading the samples. */ } drwav_uninit(pWav); - if (sampleRate) *sampleRate = pWav->sampleRate; - if (channels) *channels = pWav->channels; - if (totalSampleCount) *totalSampleCount = pWav->totalSampleCount; + if (sampleRate) { + *sampleRate = pWav->sampleRate; + } + if (channels) { + *channels = pWav->channels; + } + if (totalSampleCount) { + *totalSampleCount = pWav->totalSampleCount; + } + return pSampleData; } drwav_int32* drwav__read_and_close_s32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) { + drwav_uint64 sampleDataSize; + drwav_int32* pSampleData; + drwav_uint64 samplesRead; + drwav_assert(pWav != NULL); - drwav_uint64 sampleDataSize = pWav->totalSampleCount * sizeof(drwav_int32); + sampleDataSize = pWav->totalSampleCount * sizeof(drwav_int32); if (sampleDataSize > DRWAV_SIZE_MAX) { drwav_uninit(pWav); - return NULL; // File's too big. + return NULL; /* File's too big. */ } - drwav_int32* pSampleData = (drwav_int32*)DRWAV_MALLOC((size_t)sampleDataSize); // <-- Safe cast due to the check above. + pSampleData = (drwav_int32*)DRWAV_MALLOC((size_t)sampleDataSize); /* <-- Safe cast due to the check above. */ if (pSampleData == NULL) { drwav_uninit(pWav); - return NULL; // Failed to allocate memory. + return NULL; /* Failed to allocate memory. */ } - drwav_uint64 samplesRead = drwav_read_s32(pWav, (size_t)pWav->totalSampleCount, pSampleData); + samplesRead = drwav_read_s32(pWav, (size_t)pWav->totalSampleCount, pSampleData); if (samplesRead != pWav->totalSampleCount) { DRWAV_FREE(pSampleData); drwav_uninit(pWav); - return NULL; // There was an error reading the samples. + return NULL; /* There was an error reading the samples. */ } drwav_uninit(pWav); - if (sampleRate) *sampleRate = pWav->sampleRate; - if (channels) *channels = pWav->channels; - if (totalSampleCount) *totalSampleCount = pWav->totalSampleCount; + if (sampleRate) { + *sampleRate = pWav->sampleRate; + } + if (channels) { + *channels = pWav->channels; + } + if (totalSampleCount) { + *totalSampleCount = pWav->totalSampleCount; + } + return pSampleData; } drwav_int16* drwav_open_and_read_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) { - if (channels) *channels = 0; - if (sampleRate) *sampleRate = 0; - if (totalSampleCount) *totalSampleCount = 0; - drwav wav; + + if (channels) { + *channels = 0; + } + if (sampleRate) { + *sampleRate = 0; + } + if (totalSampleCount) { + *totalSampleCount = 0; + } + if (!drwav_init(&wav, onRead, onSeek, pUserData)) { return NULL; } @@ -3895,32 +4179,53 @@ drwav_int16* drwav_open_and_read_s16(drwav_read_proc onRead, drwav_seek_proc onS drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut) { - if (channelsOut) *channelsOut = 0; - if (sampleRateOut) *sampleRateOut = 0; - if (totalFrameCountOut) *totalFrameCountOut = 0; - unsigned int channels; unsigned int sampleRate; drwav_uint64 totalSampleCount; - drwav_int16* result = drwav_open_and_read_s16(onRead, onSeek, pUserData, &channels, &sampleRate, &totalSampleCount); + drwav_int16* result; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + result = drwav_open_and_read_s16(onRead, onSeek, pUserData, &channels, &sampleRate, &totalSampleCount); if (result == NULL) { return NULL; } - if (channelsOut) *channelsOut = channels; - if (sampleRateOut) *sampleRateOut = sampleRate; - if (totalFrameCountOut) *totalFrameCountOut = totalSampleCount / channels; + if (channelsOut) { + *channelsOut = channels; + } + if (sampleRateOut) { + *sampleRateOut = sampleRate; + } + if (totalFrameCountOut) { + *totalFrameCountOut = totalSampleCount / channels; + } return result; } float* drwav_open_and_read_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) { - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; - drwav wav; + + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalSampleCount) { + *totalSampleCount = 0; + } + if (!drwav_init(&wav, onRead, onSeek, pUserData)) { return NULL; } @@ -3930,32 +4235,53 @@ float* drwav_open_and_read_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, v float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut) { - if (channelsOut) *channelsOut = 0; - if (sampleRateOut) *sampleRateOut = 0; - if (totalFrameCountOut) *totalFrameCountOut = 0; - unsigned int channels; unsigned int sampleRate; drwav_uint64 totalSampleCount; - float* result = drwav_open_and_read_f32(onRead, onSeek, pUserData, &channels, &sampleRate, &totalSampleCount); + float* result; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + result = drwav_open_and_read_f32(onRead, onSeek, pUserData, &channels, &sampleRate, &totalSampleCount); if (result == NULL) { return NULL; } - if (channelsOut) *channelsOut = channels; - if (sampleRateOut) *sampleRateOut = sampleRate; - if (totalFrameCountOut) *totalFrameCountOut = totalSampleCount / channels; + if (channelsOut) { + *channelsOut = channels; + } + if (sampleRateOut) { + *sampleRateOut = sampleRate; + } + if (totalFrameCountOut) { + *totalFrameCountOut = totalSampleCount / channels; + } return result; } drwav_int32* drwav_open_and_read_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) { - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; - drwav wav; + + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalSampleCount) { + *totalSampleCount = 0; + } + if (!drwav_init(&wav, onRead, onSeek, pUserData)) { return NULL; } @@ -3965,21 +4291,35 @@ drwav_int32* drwav_open_and_read_s32(drwav_read_proc onRead, drwav_seek_proc onS drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut) { - if (channelsOut) *channelsOut = 0; - if (sampleRateOut) *sampleRateOut = 0; - if (totalFrameCountOut) *totalFrameCountOut = 0; - unsigned int channels; unsigned int sampleRate; drwav_uint64 totalSampleCount; - drwav_int32* result = drwav_open_and_read_s32(onRead, onSeek, pUserData, &channels, &sampleRate, &totalSampleCount); + drwav_int32* result; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + result = drwav_open_and_read_s32(onRead, onSeek, pUserData, &channels, &sampleRate, &totalSampleCount); if (result == NULL) { return NULL; } - if (channelsOut) *channelsOut = channels; - if (sampleRateOut) *sampleRateOut = sampleRate; - if (totalFrameCountOut) *totalFrameCountOut = totalSampleCount / channels; + if (channelsOut) { + *channelsOut = channels; + } + if (sampleRateOut) { + *sampleRateOut = sampleRate; + } + if (totalFrameCountOut) { + *totalFrameCountOut = totalSampleCount / channels; + } return result; } @@ -3987,11 +4327,18 @@ drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_se #ifndef DR_WAV_NO_STDIO drwav_int16* drwav_open_file_and_read_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) { - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; - drwav wav; + + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalSampleCount) { + *totalSampleCount = 0; + } + if (!drwav_init_file(&wav, filename)) { return NULL; } @@ -4001,32 +4348,53 @@ drwav_int16* drwav_open_file_and_read_s16(const char* filename, unsigned int* ch drwav_int16* drwav_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut) { - if (channelsOut) *channelsOut = 0; - if (sampleRateOut) *sampleRateOut = 0; - if (totalFrameCountOut) *totalFrameCountOut = 0; - unsigned int channels; unsigned int sampleRate; drwav_uint64 totalSampleCount; - drwav_int16* result = drwav_open_file_and_read_s16(filename, &channels, &sampleRate, &totalSampleCount); + drwav_int16* result; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + result = drwav_open_file_and_read_s16(filename, &channels, &sampleRate, &totalSampleCount); if (result == NULL) { return NULL; } - if (channelsOut) *channelsOut = channels; - if (sampleRateOut) *sampleRateOut = sampleRate; - if (totalFrameCountOut) *totalFrameCountOut = totalSampleCount / channels; + if (channelsOut) { + *channelsOut = channels; + } + if (sampleRateOut) { + *sampleRateOut = sampleRate; + } + if (totalFrameCountOut) { + *totalFrameCountOut = totalSampleCount / channels; + } return result; } float* drwav_open_file_and_read_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) { - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; - drwav wav; + + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalSampleCount) { + *totalSampleCount = 0; + } + if (!drwav_init_file(&wav, filename)) { return NULL; } @@ -4036,32 +4404,53 @@ float* drwav_open_file_and_read_f32(const char* filename, unsigned int* channels float* drwav_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut) { - if (channelsOut) *channelsOut = 0; - if (sampleRateOut) *sampleRateOut = 0; - if (totalFrameCountOut) *totalFrameCountOut = 0; - unsigned int channels; unsigned int sampleRate; drwav_uint64 totalSampleCount; - float* result = drwav_open_file_and_read_f32(filename, &channels, &sampleRate, &totalSampleCount); + float* result; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + result = drwav_open_file_and_read_f32(filename, &channels, &sampleRate, &totalSampleCount); if (result == NULL) { return NULL; } - if (channelsOut) *channelsOut = channels; - if (sampleRateOut) *sampleRateOut = sampleRate; - if (totalFrameCountOut) *totalFrameCountOut = totalSampleCount / channels; + if (channelsOut) { + *channelsOut = channels; + } + if (sampleRateOut) { + *sampleRateOut = sampleRate; + } + if (totalFrameCountOut) { + *totalFrameCountOut = totalSampleCount / channels; + } return result; } drwav_int32* drwav_open_file_and_read_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) { - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; - drwav wav; + + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalSampleCount) { + *totalSampleCount = 0; + } + if (!drwav_init_file(&wav, filename)) { return NULL; } @@ -4071,21 +4460,35 @@ drwav_int32* drwav_open_file_and_read_s32(const char* filename, unsigned int* ch drwav_int32* drwav_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut) { - if (channelsOut) *channelsOut = 0; - if (sampleRateOut) *sampleRateOut = 0; - if (totalFrameCountOut) *totalFrameCountOut = 0; - unsigned int channels; unsigned int sampleRate; drwav_uint64 totalSampleCount; - drwav_int32* result = drwav_open_file_and_read_s32(filename, &channels, &sampleRate, &totalSampleCount); + drwav_int32* result; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + result = drwav_open_file_and_read_s32(filename, &channels, &sampleRate, &totalSampleCount); if (result == NULL) { return NULL; } - if (channelsOut) *channelsOut = channels; - if (sampleRateOut) *sampleRateOut = sampleRate; - if (totalFrameCountOut) *totalFrameCountOut = totalSampleCount / channels; + if (channelsOut) { + *channelsOut = channels; + } + if (sampleRateOut) { + *sampleRateOut = sampleRate; + } + if (totalFrameCountOut) { + *totalFrameCountOut = totalSampleCount / channels; + } return result; } @@ -4093,11 +4496,18 @@ drwav_int32* drwav_open_file_and_read_pcm_frames_s32(const char* filename, unsig drwav_int16* drwav_open_memory_and_read_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) { - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; - drwav wav; + + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalSampleCount) { + *totalSampleCount = 0; + } + if (!drwav_init_memory(&wav, data, dataSize)) { return NULL; } @@ -4107,32 +4517,53 @@ drwav_int16* drwav_open_memory_and_read_s16(const void* data, size_t dataSize, u drwav_int16* drwav_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut) { - if (channelsOut) *channelsOut = 0; - if (sampleRateOut) *sampleRateOut = 0; - if (totalFrameCountOut) *totalFrameCountOut = 0; - unsigned int channels; unsigned int sampleRate; drwav_uint64 totalSampleCount; - drwav_int16* result = drwav_open_memory_and_read_s16(data, dataSize, &channels, &sampleRate, &totalSampleCount); + drwav_int16* result; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + result = drwav_open_memory_and_read_s16(data, dataSize, &channels, &sampleRate, &totalSampleCount); if (result == NULL) { return NULL; } - if (channelsOut) *channelsOut = channels; - if (sampleRateOut) *sampleRateOut = sampleRate; - if (totalFrameCountOut) *totalFrameCountOut = totalSampleCount / channels; + if (channelsOut) { + *channelsOut = channels; + } + if (sampleRateOut) { + *sampleRateOut = sampleRate; + } + if (totalFrameCountOut) { + *totalFrameCountOut = totalSampleCount / channels; + } return result; } float* drwav_open_memory_and_read_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) { - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; - drwav wav; + + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalSampleCount) { + *totalSampleCount = 0; + } + if (!drwav_init_memory(&wav, data, dataSize)) { return NULL; } @@ -4142,32 +4573,53 @@ float* drwav_open_memory_and_read_f32(const void* data, size_t dataSize, unsigne float* drwav_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut) { - if (channelsOut) *channelsOut = 0; - if (sampleRateOut) *sampleRateOut = 0; - if (totalFrameCountOut) *totalFrameCountOut = 0; - unsigned int channels; unsigned int sampleRate; drwav_uint64 totalSampleCount; - float* result = drwav_open_memory_and_read_f32(data, dataSize, &channels, &sampleRate, &totalSampleCount); + float* result; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + result = drwav_open_memory_and_read_f32(data, dataSize, &channels, &sampleRate, &totalSampleCount); if (result == NULL) { return NULL; } - if (channelsOut) *channelsOut = channels; - if (sampleRateOut) *sampleRateOut = sampleRate; - if (totalFrameCountOut) *totalFrameCountOut = totalSampleCount / channels; + if (channelsOut) { + *channelsOut = channels; + } + if (sampleRateOut) { + *sampleRateOut = sampleRate; + } + if (totalFrameCountOut) { + *totalFrameCountOut = totalSampleCount / channels; + } return result; } drwav_int32* drwav_open_memory_and_read_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount) { - if (sampleRate) *sampleRate = 0; - if (channels) *channels = 0; - if (totalSampleCount) *totalSampleCount = 0; - drwav wav; + + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalSampleCount) { + *totalSampleCount = 0; + } + if (!drwav_init_memory(&wav, data, dataSize)) { return NULL; } @@ -4177,25 +4629,39 @@ drwav_int32* drwav_open_memory_and_read_s32(const void* data, size_t dataSize, u drwav_int32* drwav_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut) { - if (channelsOut) *channelsOut = 0; - if (sampleRateOut) *sampleRateOut = 0; - if (totalFrameCountOut) *totalFrameCountOut = 0; - unsigned int channels; unsigned int sampleRate; drwav_uint64 totalSampleCount; - drwav_int32* result = drwav_open_memory_and_read_s32(data, dataSize, &channels, &sampleRate, &totalSampleCount); + drwav_int32* result; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + result = drwav_open_memory_and_read_s32(data, dataSize, &channels, &sampleRate, &totalSampleCount); if (result == NULL) { return NULL; } - if (channelsOut) *channelsOut = channels; - if (sampleRateOut) *sampleRateOut = sampleRate; - if (totalFrameCountOut) *totalFrameCountOut = totalSampleCount / channels; + if (channelsOut) { + *channelsOut = channels; + } + if (sampleRateOut) { + *sampleRateOut = sampleRate; + } + if (totalFrameCountOut) { + *totalFrameCountOut = totalSampleCount / channels; + } return result; } -#endif //DR_WAV_NO_CONVERSION_API +#endif /* DR_WAV_NO_CONVERSION_API */ void drwav_free(void* pDataReturnedByOpenAndRead) @@ -4203,175 +4669,203 @@ void drwav_free(void* pDataReturnedByOpenAndRead) DRWAV_FREE(pDataReturnedByOpenAndRead); } -#endif //DR_WAV_IMPLEMENTATION - - -// REVISION HISTORY -// -// v0.9.0 - 2018-12-16 -// - API CHANGE: Add new reading APIs for reading by PCM frames instead of samples. Old APIs have been deprecated and -// will be removed in v0.10.0. Deprecated APIs and their replacements: -// drwav_read() -> drwav_read_pcm_frames() -// drwav_read_s16() -> drwav_read_pcm_frames_s16() -// drwav_read_f32() -> drwav_read_pcm_frames_f32() -// drwav_read_s32() -> drwav_read_pcm_frames_s32() -// drwav_seek_to_sample() -> drwav_seek_to_pcm_frame() -// drwav_write() -> drwav_write_pcm_frames() -// drwav_open_and_read_s16() -> drwav_open_and_read_pcm_frames_s16() -// drwav_open_and_read_f32() -> drwav_open_and_read_pcm_frames_f32() -// drwav_open_and_read_s32() -> drwav_open_and_read_pcm_frames_s32() -// drwav_open_file_and_read_s16() -> drwav_open_file_and_read_pcm_frames_s16() -// drwav_open_file_and_read_f32() -> drwav_open_file_and_read_pcm_frames_f32() -// drwav_open_file_and_read_s32() -> drwav_open_file_and_read_pcm_frames_s32() -// drwav_open_memory_and_read_s16() -> drwav_open_memory_and_read_pcm_frames_s16() -// drwav_open_memory_and_read_f32() -> drwav_open_memory_and_read_pcm_frames_f32() -// drwav_open_memory_and_read_s32() -> drwav_open_memory_and_read_pcm_frames_s32() -// drwav::totalSampleCount -> drwav::totalPCMFrameCount -// - API CHANGE: Rename drwav_open_and_read_file_*() to drwav_open_file_and_read_*(). -// - API CHANGE: Rename drwav_open_and_read_memory_*() to drwav_open_memory_and_read_*(). -// - Add built-in support for smpl chunks. -// - Add support for firing a callback for each chunk in the file at initialization time. -// - This is enabled through the drwav_init_ex(), etc. family of APIs. -// - Handle invalid FMT chunks more robustly. -// -// v0.8.5 - 2018-09-11 -// - Const correctness. -// - Fix a potential stack overflow. -// -// v0.8.4 - 2018-08-07 -// - Improve 64-bit detection. -// -// v0.8.3 - 2018-08-05 -// - Fix C++ build on older versions of GCC. -// -// v0.8.2 - 2018-08-02 -// - Fix some big-endian bugs. -// -// v0.8.1 - 2018-06-29 -// - Add support for sequential writing APIs. -// - Disable seeking in write mode. -// - Fix bugs with Wave64. -// - Fix typos. -// -// v0.8 - 2018-04-27 -// - Bug fix. -// - Start using major.minor.revision versioning. -// -// v0.7f - 2018-02-05 -// - Restrict ADPCM formats to a maximum of 2 channels. -// -// v0.7e - 2018-02-02 -// - Fix a crash. -// -// v0.7d - 2018-02-01 -// - Fix a crash. -// -// v0.7c - 2018-02-01 -// - Set drwav.bytesPerSample to 0 for all compressed formats. -// - Fix a crash when reading 16-bit floating point WAV files. In this case dr_wav will output silence for -// all format conversion reading APIs (*_s16, *_s32, *_f32 APIs). -// - Fix some divide-by-zero errors. -// -// v0.7b - 2018-01-22 -// - Fix errors with seeking of compressed formats. -// - Fix compilation error when DR_WAV_NO_CONVERSION_API -// -// v0.7a - 2017-11-17 -// - Fix some GCC warnings. -// -// v0.7 - 2017-11-04 -// - Add writing APIs. -// -// v0.6 - 2017-08-16 -// - API CHANGE: Rename dr_* types to drwav_*. -// - Add support for custom implementations of malloc(), realloc(), etc. -// - Add support for Microsoft ADPCM. -// - Add support for IMA ADPCM (DVI, format code 0x11). -// - Optimizations to drwav_read_s16(). -// - Bug fixes. -// -// v0.5g - 2017-07-16 -// - Change underlying type for booleans to unsigned. -// -// v0.5f - 2017-04-04 -// - Fix a minor bug with drwav_open_and_read_s16() and family. -// -// v0.5e - 2016-12-29 -// - Added support for reading samples as signed 16-bit integers. Use the _s16() family of APIs for this. -// - Minor fixes to documentation. -// -// v0.5d - 2016-12-28 -// - Use drwav_int*/drwav_uint* sized types to improve compiler support. -// -// v0.5c - 2016-11-11 -// - Properly handle JUNK chunks that come before the FMT chunk. -// -// v0.5b - 2016-10-23 -// - A minor change to drwav_bool8 and drwav_bool32 types. -// -// v0.5a - 2016-10-11 -// - Fixed a bug with drwav_open_and_read() and family due to incorrect argument ordering. -// - Improve A-law and mu-law efficiency. -// -// v0.5 - 2016-09-29 -// - API CHANGE. Swap the order of "channels" and "sampleRate" parameters in drwav_open_and_read*(). Rationale for this is to -// keep it consistent with dr_audio and dr_flac. -// -// v0.4b - 2016-09-18 -// - Fixed a typo in documentation. -// -// v0.4a - 2016-09-18 -// - Fixed a typo. -// - Change date format to ISO 8601 (YYYY-MM-DD) -// -// v0.4 - 2016-07-13 -// - API CHANGE. Make onSeek consistent with dr_flac. -// - API CHANGE. Rename drwav_seek() to drwav_seek_to_sample() for clarity and consistency with dr_flac. -// - Added support for Sony Wave64. -// -// v0.3a - 2016-05-28 -// - API CHANGE. Return drwav_bool32 instead of int in onSeek callback. -// - Fixed a memory leak. -// -// v0.3 - 2016-05-22 -// - Lots of API changes for consistency. -// -// v0.2a - 2016-05-16 -// - Fixed Linux/GCC build. -// -// v0.2 - 2016-05-11 -// - Added support for reading data as signed 32-bit PCM for consistency with dr_flac. -// -// v0.1a - 2016-05-07 -// - Fixed a bug in drwav_open_file() where the file handle would not be closed if the loader failed to initialize. -// -// v0.1 - 2016-05-04 -// - Initial versioned release. +#endif /* DR_WAV_IMPLEMENTATION */ /* +REVISION HISTORY +================ +v0.9.1 - 2019-05-05 + - Add support for C89. + - Change license to choice of public domain or MIT-0. + +v0.9.0 - 2018-12-16 + - API CHANGE: Add new reading APIs for reading by PCM frames instead of samples. Old APIs have been deprecated and + will be removed in v0.10.0. Deprecated APIs and their replacements: + drwav_read() -> drwav_read_pcm_frames() + drwav_read_s16() -> drwav_read_pcm_frames_s16() + drwav_read_f32() -> drwav_read_pcm_frames_f32() + drwav_read_s32() -> drwav_read_pcm_frames_s32() + drwav_seek_to_sample() -> drwav_seek_to_pcm_frame() + drwav_write() -> drwav_write_pcm_frames() + drwav_open_and_read_s16() -> drwav_open_and_read_pcm_frames_s16() + drwav_open_and_read_f32() -> drwav_open_and_read_pcm_frames_f32() + drwav_open_and_read_s32() -> drwav_open_and_read_pcm_frames_s32() + drwav_open_file_and_read_s16() -> drwav_open_file_and_read_pcm_frames_s16() + drwav_open_file_and_read_f32() -> drwav_open_file_and_read_pcm_frames_f32() + drwav_open_file_and_read_s32() -> drwav_open_file_and_read_pcm_frames_s32() + drwav_open_memory_and_read_s16() -> drwav_open_memory_and_read_pcm_frames_s16() + drwav_open_memory_and_read_f32() -> drwav_open_memory_and_read_pcm_frames_f32() + drwav_open_memory_and_read_s32() -> drwav_open_memory_and_read_pcm_frames_s32() + drwav::totalSampleCount -> drwav::totalPCMFrameCount + - API CHANGE: Rename drwav_open_and_read_file_*() to drwav_open_file_and_read_*(). + - API CHANGE: Rename drwav_open_and_read_memory_*() to drwav_open_memory_and_read_*(). + - Add built-in support for smpl chunks. + - Add support for firing a callback for each chunk in the file at initialization time. + - This is enabled through the drwav_init_ex(), etc. family of APIs. + - Handle invalid FMT chunks more robustly. + +v0.8.5 - 2018-09-11 + - Const correctness. + - Fix a potential stack overflow. + +v0.8.4 - 2018-08-07 + - Improve 64-bit detection. + +v0.8.3 - 2018-08-05 + - Fix C++ build on older versions of GCC. + +v0.8.2 - 2018-08-02 + - Fix some big-endian bugs. + +v0.8.1 - 2018-06-29 + - Add support for sequential writing APIs. + - Disable seeking in write mode. + - Fix bugs with Wave64. + - Fix typos. + +v0.8 - 2018-04-27 + - Bug fix. + - Start using major.minor.revision versioning. + +v0.7f - 2018-02-05 + - Restrict ADPCM formats to a maximum of 2 channels. + +v0.7e - 2018-02-02 + - Fix a crash. + +v0.7d - 2018-02-01 + - Fix a crash. + +v0.7c - 2018-02-01 + - Set drwav.bytesPerSample to 0 for all compressed formats. + - Fix a crash when reading 16-bit floating point WAV files. In this case dr_wav will output silence for + all format conversion reading APIs (*_s16, *_s32, *_f32 APIs). + - Fix some divide-by-zero errors. + +v0.7b - 2018-01-22 + - Fix errors with seeking of compressed formats. + - Fix compilation error when DR_WAV_NO_CONVERSION_API + +v0.7a - 2017-11-17 + - Fix some GCC warnings. + +v0.7 - 2017-11-04 + - Add writing APIs. + +v0.6 - 2017-08-16 + - API CHANGE: Rename dr_* types to drwav_*. + - Add support for custom implementations of malloc(), realloc(), etc. + - Add support for Microsoft ADPCM. + - Add support for IMA ADPCM (DVI, format code 0x11). + - Optimizations to drwav_read_s16(). + - Bug fixes. + +v0.5g - 2017-07-16 + - Change underlying type for booleans to unsigned. + +v0.5f - 2017-04-04 + - Fix a minor bug with drwav_open_and_read_s16() and family. + +v0.5e - 2016-12-29 + - Added support for reading samples as signed 16-bit integers. Use the _s16() family of APIs for this. + - Minor fixes to documentation. + +v0.5d - 2016-12-28 + - Use drwav_int* and drwav_uint* sized types to improve compiler support. + +v0.5c - 2016-11-11 + - Properly handle JUNK chunks that come before the FMT chunk. + +v0.5b - 2016-10-23 + - A minor change to drwav_bool8 and drwav_bool32 types. + +v0.5a - 2016-10-11 + - Fixed a bug with drwav_open_and_read() and family due to incorrect argument ordering. + - Improve A-law and mu-law efficiency. + +v0.5 - 2016-09-29 + - API CHANGE. Swap the order of "channels" and "sampleRate" parameters in drwav_open_and_read*(). Rationale for this is to + keep it consistent with dr_audio and dr_flac. + +v0.4b - 2016-09-18 + - Fixed a typo in documentation. + +v0.4a - 2016-09-18 + - Fixed a typo. + - Change date format to ISO 8601 (YYYY-MM-DD) + +v0.4 - 2016-07-13 + - API CHANGE. Make onSeek consistent with dr_flac. + - API CHANGE. Rename drwav_seek() to drwav_seek_to_sample() for clarity and consistency with dr_flac. + - Added support for Sony Wave64. + +v0.3a - 2016-05-28 + - API CHANGE. Return drwav_bool32 instead of int in onSeek callback. + - Fixed a memory leak. + +v0.3 - 2016-05-22 + - Lots of API changes for consistency. + +v0.2a - 2016-05-16 + - Fixed Linux/GCC build. + +v0.2 - 2016-05-11 + - Added support for reading data as signed 32-bit PCM for consistency with dr_flac. + +v0.1a - 2016-05-07 + - Fixed a bug in drwav_open_file() where the file handle would not be closed if the loader failed to initialize. + +v0.1 - 2016-05-04 + - Initial versioned release. +*/ + +/* +This software is available as a choice of the following licenses. Choose +whichever you prefer. + +=============================================================================== +ALTERNATIVE 1 - Public Domain (www.unlicense.org) +=============================================================================== This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to + +=============================================================================== +ALTERNATIVE 2 - MIT No Attribution +=============================================================================== +Copyright 2018 David Reid + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. */