forked from mackron/dr_libs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdr_flac.h
4415 lines (3674 loc) · 175 KB
/
dr_flac.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// FLAC audio decoder. Public domain. See "unlicense" statement at the end of this file.
// dr_flac - v0.4b - 2016-10-23
//
// 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
// }
//
// int32_t* pSamples = malloc(pFlac->totalSampleCount * sizeof(int32_t));
// uint64_t numberOfInterleavedSamplesActuallyRead = drflac_read_s32(pFlac, pFlac->totalSampleCount, 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_s32(pFlac, chunkSize, 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;
// uint64_t totalSampleCount;
// int32_t* pSampleData = drflac_open_and_decode_file("MySong.flac", &channels, &sampleRate, &totalSampleCount);
// if (pSampleData == NULL) {
// // Failed to open and decode FLAC file.
// }
//
// ...
//
// drflac_free(pSampleData);
//
//
// 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. See https://github.com/mackron/dr_libs_tests/blob/master/dr_flac/dr_flac_test_2.c for
// an example on how to read metadata.
//
//
//
// OPTIONS
// #define these options before including this file.
//
// #define DR_FLAC_NO_STDIO
// Disable drflac_open_file().
//
// #define DR_FLAC_NO_OGG
// Disables support for Ogg/FLAC streams.
//
// #define DR_FLAC_NO_WIN32_IO
// In the Win32 build, dr_flac uses the Win32 IO APIs for drflac_open_file() by default. This setting will make it use the
// standard FILE APIs instead. Ignored when DR_FLAC_NO_STDIO is #defined. (The rationale for this configuration is that
// there's a bug in one compiler's Win32 implementation of the FILE APIs which is not present in the Win32 IO APIs.)
//
// #define DR_FLAC_BUFFER_SIZE <number>
// Defines the size of the internal buffer to store data from onRead(). This buffer is used to reduce the number of calls
// back to the client for more data. Larger values means more memory, but better performance. My tests show diminishing
// returns after about 4KB (which is the default). Consider reducing this if you have a very efficient implementation of
// onRead(), or increase it if it's very inefficient. Must be a multiple of 8.
//
//
//
// QUICK NOTES
// - Based on my tests, the performance of the 32-bit build is at about parity with the reference implementation. The 64-bit build
// is slightly faster.
// - dr_flac does not currently do any CRC checks.
// - dr_flac should work fine with valid native FLAC files, but for broadcast streams it won't work if the header and STREAMINFO
// block is unavailable.
// - 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.
// - Rice codes in unencoded binary form (see https://xiph.org/flac/format.html#rice_partition) has not been tested. If anybody
// knows where I can find some test files for this, let me know.
// - Perverse and erroneous files have not been tested. Again, if you know where I can get some test files let me know.
// - dr_flac is not thread-safe, but it's APIs can be called from any thread so long as you do your own synchronization.
#ifndef dr_flac_h
#define dr_flac_h
#include <stdint.h>
#include <stddef.h>
#ifndef DR_SIZED_TYPES_DEFINED
#define DR_SIZED_TYPES_DEFINED
#if defined(_MSC_VER) && _MSC_VER < 1600
typedef signed char dr_int8;
typedef unsigned char dr_uint8;
typedef signed short dr_int16;
typedef unsigned short dr_uint16;
typedef signed int dr_int32;
typedef unsigned int dr_uint32;
typedef signed __int64 dr_int64;
typedef unsigned __int64 dr_uint64;
#else
#include <stdint.h>
typedef int8_t dr_int8;
typedef uint8_t dr_uint8;
typedef int16_t dr_int16;
typedef uint16_t dr_uint16;
typedef int32_t dr_int32;
typedef uint32_t dr_uint32;
typedef int64_t dr_int64;
typedef uint64_t dr_uint64;
#endif
typedef dr_int8 dr_bool8;
typedef dr_int32 dr_bool32;
#define DR_TRUE 1
#define DR_FALSE 0
#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.
#ifndef DR_FLAC_BUFFER_SIZE
#define DR_FLAC_BUFFER_SIZE 4096
#endif
#ifdef __cplusplus
extern "C" {
#endif
// Check if we can enable 64-bit optimizations.
#if defined(_WIN64)
#define DRFLAC_64BIT
#endif
#if defined(__GNUC__)
#if defined(__x86_64__) || defined(__ppc64__)
#define DRFLAC_64BIT
#endif
#endif
#ifdef DRFLAC_64BIT
typedef uint64_t drflac_cache_t;
#else
typedef uint32_t drflac_cache_t;
#endif
// The various metadata block types.
#define DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO 0
#define DRFLAC_METADATA_BLOCK_TYPE_PADDING 1
#define DRFLAC_METADATA_BLOCK_TYPE_APPLICATION 2
#define DRFLAC_METADATA_BLOCK_TYPE_SEEKTABLE 3
#define DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT 4
#define DRFLAC_METADATA_BLOCK_TYPE_CUESHEET 5
#define DRFLAC_METADATA_BLOCK_TYPE_PICTURE 6
#define DRFLAC_METADATA_BLOCK_TYPE_INVALID 127
// The various picture types specified in the PICTURE block.
#define DRFLAC_PICTURE_TYPE_OTHER 0
#define DRFLAC_PICTURE_TYPE_FILE_ICON 1
#define DRFLAC_PICTURE_TYPE_OTHER_FILE_ICON 2
#define DRFLAC_PICTURE_TYPE_COVER_FRONT 3
#define DRFLAC_PICTURE_TYPE_COVER_BACK 4
#define DRFLAC_PICTURE_TYPE_LEAFLET_PAGE 5
#define DRFLAC_PICTURE_TYPE_MEDIA 6
#define DRFLAC_PICTURE_TYPE_LEAD_ARTIST 7
#define DRFLAC_PICTURE_TYPE_ARTIST 8
#define DRFLAC_PICTURE_TYPE_CONDUCTOR 9
#define DRFLAC_PICTURE_TYPE_BAND 10
#define DRFLAC_PICTURE_TYPE_COMPOSER 11
#define DRFLAC_PICTURE_TYPE_LYRICIST 12
#define DRFLAC_PICTURE_TYPE_RECORDING_LOCATION 13
#define DRFLAC_PICTURE_TYPE_DURING_RECORDING 14
#define DRFLAC_PICTURE_TYPE_DURING_PERFORMANCE 15
#define DRFLAC_PICTURE_TYPE_SCREEN_CAPTURE 16
#define DRFLAC_PICTURE_TYPE_BRIGHT_COLORED_FISH 17
#define DRFLAC_PICTURE_TYPE_ILLUSTRATION 18
#define DRFLAC_PICTURE_TYPE_BAND_LOGOTYPE 19
#define DRFLAC_PICTURE_TYPE_PUBLISHER_LOGOTYPE 20
typedef enum
{
drflac_container_native,
drflac_container_ogg
} drflac_container;
typedef enum
{
drflac_seek_origin_start,
drflac_seek_origin_current
} drflac_seek_origin;
// Packing is important on this structure because we map this directly to the raw data within the SEEKTABLE metadata block.
#pragma pack(2)
typedef struct
{
uint64_t firstSample;
uint64_t frameOffset; // The offset from the first byte of the header of the first frame.
uint16_t sampleCount;
} drflac_seekpoint;
#pragma pack()
typedef struct
{
uint16_t minBlockSize;
uint16_t maxBlockSize;
uint32_t minFrameSize;
uint32_t maxFrameSize;
uint32_t sampleRate;
uint8_t channels;
uint8_t bitsPerSample;
uint64_t totalSampleCount;
uint8_t md5[16];
} drflac_streaminfo;
typedef struct
{
// The metadata type. Use this to know how to interpret the data below.
uint32_t type;
// A pointer to the raw data. This points to a temporary buffer so don't hold on to it. It's best to
// not modify the contents of this buffer. Use the structures below for more meaningful and structured
// information about the metadata. It's possible for this to be null.
const void* pRawData;
// The size in bytes of the block and the buffer pointed to by pRawData if it's non-NULL.
uint32_t rawDataSize;
union
{
drflac_streaminfo streaminfo;
struct
{
int unused;
} padding;
struct
{
uint32_t id;
const void* pData;
uint32_t dataSize;
} application;
struct
{
uint32_t seekpointCount;
const drflac_seekpoint* pSeekpoints;
} seektable;
struct
{
uint32_t vendorLength;
const char* vendor;
uint32_t commentCount;
const char* comments;
} vorbis_comment;
struct
{
char catalog[128];
uint64_t leadInSampleCount;
dr_bool32 isCD;
uint8_t trackCount;
const uint8_t* pTrackData;
} cuesheet;
struct
{
uint32_t type;
uint32_t mimeLength;
const char* mime;
uint32_t descriptionLength;
const char* description;
uint32_t width;
uint32_t height;
uint32_t colorDepth;
uint32_t indexColorCount;
uint32_t pictureDataSize;
const uint8_t* pPictureData;
} picture;
} data;
} 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.
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.
typedef dr_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.
typedef void (* drflac_meta_proc)(void* pUserData, drflac_metadata* pMetadata);
// Structure for internal use. Only used for decoders opened with drflac_open_memory.
typedef struct
{
const uint8_t* data;
size_t dataSize;
size_t currentReadPos;
} drflac__memory_stream;
// Structure for internal use. Used for bit streaming.
typedef struct
{
// The function to call when more data needs to be read.
drflac_read_proc onRead;
// The function to call when the current read position needs to be moved.
drflac_seek_proc onSeek;
// The user data to pass around to onRead and onSeek.
void* pUserData;
// The number of unaligned bytes in the L2 cache. This will always be 0 until the end of the stream is hit. At the end of the
// stream there will be a number of bytes that don't cleanly fit in an L1 cache line, so we use this variable to know whether
// or not the bistreamer needs to run on a slower path to read those last bytes. This will never be more than sizeof(drflac_cache_t).
size_t unalignedByteCount;
// The content of the unaligned bytes.
drflac_cache_t unalignedCache;
// The index of the next valid cache line in the "L2" cache.
size_t nextL2Line;
// The number of bits that have been consumed by the cache. This is used to determine how many valid bits are remaining.
size_t consumedBits;
// The cached data which was most recently read from the client. There are two levels of cache. Data flows as such:
// Client -> L2 -> L1. The L2 -> L1 movement is aligned and runs on a fast path in just a few instructions.
drflac_cache_t cacheL2[DR_FLAC_BUFFER_SIZE/sizeof(drflac_cache_t)];
drflac_cache_t cache;
} drflac_bs;
typedef struct
{
// The type of the subframe: SUBFRAME_CONSTANT, SUBFRAME_VERBATIM, SUBFRAME_FIXED or SUBFRAME_LPC.
uint8_t subframeType;
// The number of wasted bits per sample as specified by the sub-frame header.
uint8_t wastedBitsPerSample;
// The order to use for the prediction stage for SUBFRAME_FIXED and SUBFRAME_LPC.
uint8_t 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.
uint32_t bitsPerSample;
// A pointer to the buffer containing the decoded samples in the subframe. This pointer is an offset from drflac::pExtraData, or
// NULL if the heap is not being used. Note that it's a signed 32-bit integer for each value.
int32_t* 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.
uint64_t 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.
uint32_t frameNumber;
// The sample rate of this frame.
uint32_t sampleRate;
// The number of samples in each sub-frame within this frame.
uint16_t 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.
uint8_t channelAssignment;
// The number of bits per sample within this frame.
uint8_t bitsPerSample;
// The frame's CRC. This is set, but unused at the moment.
uint8_t crc8;
} drflac_frame_header;
typedef struct
{
// 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.
uint32_t 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.
drflac_subframe subframes[8];
} drflac_frame;
typedef struct
{
// The function to call when a metadata block is read.
drflac_meta_proc onMeta;
// The user data posted to the metadata callback function.
void* pUserDataMD;
// The sample rate. Will be set to something like 44100.
uint32_t 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.
uint8_t channels;
// The bits per sample. Will be set to somthing like 16, 24, etc.
uint8_t bitsPerSample;
// The maximum block size, in samples. This number represents the number of samples in each channel (not combined).
uint16_t 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.
uint64_t totalSampleCount;
// 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 position of the seektable in the file.
uint64_t seektablePos;
// The size of the seektable.
uint32_t seektableSize;
// Information about the frame the decoder is currently sitting on.
drflac_frame currentFrame;
// The position of the first frame in the stream. This is only ever used for seeking.
uint64_t firstFramePos;
// 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.
int32_t* pDecodedSamples;
// 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 avoid unnecessary mallocs.
uint8_t 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.
//
// 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);
// 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 malloc()
// and 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 with be handled before the function
// returns.
//
// 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);
// 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.
// samplesToRead [in] The number of samples to read.
// pBufferOut [out, optional] A pointer to the buffer that will receive the decoded samples.
//
// Returns the number of samples 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 samples
// seeked.
uint64_t drflac_read_s32(drflac* pFlac, uint64_t samplesToRead, int32_t* pBufferOut);
// Seeks to the sample at the given index.
//
// pFlac [in] The decoder.
// sampleIndex [in] The index of the sample to seek to. See notes below.
//
// Returns DR_TRUE if successful; DR_FALSE otherwise.
//
// The sample index is based on interleaving. In a stereo stream, for example, the sample at index 0 is the first sample
// in the left channel; the sample at index 1 is the first sample on the right channel, and so on.
//
// When seeking, you will likely want to ensure it's rounded to a multiple of the channel count. You can do this with
// something like drflac_seek_to_sample(pFlac, (mySampleIndex + (mySampleIndex % pFlac->channels)))
dr_bool32 drflac_seek_to_sample(drflac* pFlac, uint64_t sampleIndex);
#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()
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.
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.
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.
drflac* drflac_open_memory_with_metadata(const void* data, size_t dataSize, drflac_meta_proc onMeta, void* pUserData);
//// 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).
int32_t* drflac_open_and_decode_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount);
#ifndef DR_FLAC_NO_STDIO
// Same as drflac_open_and_decode_s32() except opens the decoder from a file.
int32_t* drflac_open_and_decode_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount);
#endif
// Same as drflac_open_and_decode_s32() except opens the decoder from a block of memory.
int32_t* drflac_open_and_decode_memory_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount);
// Frees data returned by drflac_open_and_decode_*().
void drflac_free(void* pSampleDataReturnedByOpenAndDecode);
// Structure representing an iterator for vorbis comments in a VORBIS_COMMENT metadata block.
typedef struct
{
uint32_t 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.
void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, uint32_t commentCount, const char* 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.
const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, uint32_t* pCommentLengthOut);
#ifdef __cplusplus
}
#endif
#endif //dr_flac_h
///////////////////////////////////////////////////////////////////////////////
//
// IMPLEMENTATION
//
///////////////////////////////////////////////////////////////////////////////
#ifdef DR_FLAC_IMPLEMENTATION
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#ifdef _MSC_VER
#include <intrin.h> // For _byteswap_ulong and _byteswap_uint64
#endif
#ifdef __linux__
#define _BSD_SOURCE
#include <endian.h>
#endif
#ifdef _MSC_VER
#define DRFLAC_INLINE __forceinline
#else
#define DRFLAC_INLINE inline
#endif
#define DRFLAC_SUBFRAME_CONSTANT 0
#define DRFLAC_SUBFRAME_VERBATIM 1
#define DRFLAC_SUBFRAME_FIXED 8
#define DRFLAC_SUBFRAME_LPC 32
#define DRFLAC_SUBFRAME_RESERVED 255
#define DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE 0
#define DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2 1
#define DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT 0
#define DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE 8
#define DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE 9
#define DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE 10
//// Endian Management ////
static DRFLAC_INLINE dr_bool32 drflac__is_little_endian()
{
int n = 1;
return (*(char*)&n) == 1;
}
static DRFLAC_INLINE uint16_t drflac__swap_endian_uint16(uint16_t n)
{
#ifdef _MSC_VER
return _byteswap_ushort(n);
#elif defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
return __builtin_bswap16(n);
#else
return ((n & 0xFF00) >> 8) |
((n & 0x00FF) << 8);
#endif
}
static DRFLAC_INLINE uint32_t drflac__swap_endian_uint32(uint32_t n)
{
#ifdef _MSC_VER
return _byteswap_ulong(n);
#elif defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
return __builtin_bswap32(n);
#else
return ((n & 0xFF000000) >> 24) |
((n & 0x00FF0000) >> 8) |
((n & 0x0000FF00) << 8) |
((n & 0x000000FF) << 24);
#endif
}
static DRFLAC_INLINE uint64_t drflac__swap_endian_uint64(uint64_t n)
{
#ifdef _MSC_VER
return _byteswap_uint64(n);
#elif defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
return __builtin_bswap64(n);
#else
return ((n & 0xFF00000000000000ULL) >> 56) |
((n & 0x00FF000000000000ULL) >> 40) |
((n & 0x0000FF0000000000ULL) >> 24) |
((n & 0x000000FF00000000ULL) >> 8) |
((n & 0x00000000FF000000ULL) << 8) |
((n & 0x0000000000FF0000ULL) << 24) |
((n & 0x000000000000FF00ULL) << 40) |
((n & 0x00000000000000FFULL) << 56);
#endif
}
static DRFLAC_INLINE uint16_t drflac__be2host_16(uint16_t n)
{
#ifdef __linux__
return be16toh(n);
#else
if (drflac__is_little_endian()) {
return drflac__swap_endian_uint16(n);
}
return n;
#endif
}
static DRFLAC_INLINE uint32_t drflac__be2host_32(uint32_t n)
{
#ifdef __linux__
return be32toh(n);
#else
if (drflac__is_little_endian()) {
return drflac__swap_endian_uint32(n);
}
return n;
#endif
}
static DRFLAC_INLINE uint64_t drflac__be2host_64(uint64_t n)
{
#ifdef __linux__
return be64toh(n);
#else
if (drflac__is_little_endian()) {
return drflac__swap_endian_uint64(n);
}
return n;
#endif
}
static DRFLAC_INLINE uint32_t drflac__le2host_32(uint32_t n)
{
#ifdef __linux__
return le32toh(n);
#else
if (!drflac__is_little_endian()) {
return drflac__swap_endian_uint32(n);
}
return n;
#endif
}
#ifdef DRFLAC_64BIT
#define drflac__be2host__cache_line drflac__be2host_64
#else
#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.
#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))
#ifdef DRFLAC_64BIT
#define DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount) (~(((uint64_t)-1LL) >> (_bitCount)))
#else
#define DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount) (~(((uint32_t)-1) >> (_bitCount)))
#endif
#define DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, _bitCount) (DRFLAC_CACHE_L1_SIZE_BITS(bs) - (_bitCount))
#define DRFLAC_CACHE_L1_SELECT(bs, _bitCount) (((bs)->cache) & DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount))
#define DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, _bitCount) (DRFLAC_CACHE_L1_SELECT((bs), _bitCount) >> DRFLAC_CACHE_L1_SELECTION_SHIFT((bs), _bitCount))
#define DRFLAC_CACHE_L2_SIZE_BYTES(bs) (sizeof((bs)->cacheL2))
#define DRFLAC_CACHE_L2_LINE_COUNT(bs) (DRFLAC_CACHE_L2_SIZE_BYTES(bs) / sizeof((bs)->cacheL2[0]))
#define DRFLAC_CACHE_L2_LINES_REMAINING(bs) (DRFLAC_CACHE_L2_LINE_COUNT(bs) - (bs)->nextL2Line)
static DRFLAC_INLINE dr_bool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs)
{
// Fast path. Try loading straight from L2.
if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
bs->cache = bs->cacheL2[bs->nextL2Line++];
return DR_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 (bs->unalignedByteCount > 0) {
return DR_FALSE; // If we have any unaligned bytes it means there's not more aligned bytes left in the client.
}
size_t bytesRead = bs->onRead(bs->pUserData, bs->cacheL2, DRFLAC_CACHE_L2_SIZE_BYTES(bs));
bs->nextL2Line = 0;
if (bytesRead == DRFLAC_CACHE_L2_SIZE_BYTES(bs)) {
bs->cache = bs->cacheL2[bs->nextL2Line++];
return DR_TRUE;
}
// 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);
// 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];
}
if (alignedL1LineCount > 0)
{
size_t offset = DRFLAC_CACHE_L2_LINE_COUNT(bs) - alignedL1LineCount;
for (size_t i = alignedL1LineCount; i > 0; --i) {
bs->cacheL2[i-1 + offset] = bs->cacheL2[i-1];
}
bs->nextL2Line = offset;
bs->cache = bs->cacheL2[bs->nextL2Line++];
return DR_TRUE;
}
else
{
// 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 DR_FALSE;
}
}
static dr_bool32 drflac__reload_cache(drflac_bs* bs)
{
// 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;
return DR_TRUE;
}
// 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 (bytesRead == 0) {
return DR_FALSE;
}
assert(bytesRead < DRFLAC_CACHE_L1_SIZE_BYTES(bs));
bs->consumedBits = (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_SIZE_BITS(bs) - bs->consumedBits); // <-- Make sure the consumed bits are always set to zero. Other parts of the library depend on this property.
return DR_TRUE;
}
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->cache = 0;
bs->unalignedByteCount = 0; // <-- This clears the trailing unaligned bytes.
bs->unalignedCache = 0;
}
static dr_bool32 drflac__seek_bits(drflac_bs* bs, size_t bitsToSeek)
{
if (bitsToSeek <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
bs->consumedBits += bitsToSeek;
bs->cache <<= bitsToSeek;
return DR_TRUE;
} else {
// It straddles the cached data. This function isn't called too frequently so I'm favouring simplicity here.
bitsToSeek -= DRFLAC_CACHE_L1_BITS_REMAINING(bs);
bs->consumedBits += DRFLAC_CACHE_L1_BITS_REMAINING(bs);
bs->cache = 0;
size_t wholeBytesRemaining = bitsToSeek/8;
if (wholeBytesRemaining > 0)
{
// The next bytes to seek will be located in the L2 cache. The problem is that the L2 cache is not byte aligned,
// but rather DRFLAC_CACHE_L1_SIZE_BYTES aligned (usually 4 or 8). If, for example, the number of bytes to seek is
// 3, we'll need to handle it in a special way.
size_t wholeCacheLinesRemaining = wholeBytesRemaining / DRFLAC_CACHE_L1_SIZE_BYTES(bs);
if (wholeCacheLinesRemaining < DRFLAC_CACHE_L2_LINES_REMAINING(bs))
{
wholeBytesRemaining -= wholeCacheLinesRemaining * DRFLAC_CACHE_L1_SIZE_BYTES(bs);
bitsToSeek -= wholeCacheLinesRemaining * DRFLAC_CACHE_L1_SIZE_BITS(bs);
bs->nextL2Line += wholeCacheLinesRemaining;
}
else
{
wholeBytesRemaining -= DRFLAC_CACHE_L2_LINES_REMAINING(bs) * DRFLAC_CACHE_L1_SIZE_BYTES(bs);
bitsToSeek -= DRFLAC_CACHE_L2_LINES_REMAINING(bs) * DRFLAC_CACHE_L1_SIZE_BITS(bs);
bs->nextL2Line += DRFLAC_CACHE_L2_LINES_REMAINING(bs);
if (wholeBytesRemaining > 0) {
bs->onSeek(bs->pUserData, (int)wholeBytesRemaining, drflac_seek_origin_current);
bitsToSeek -= wholeBytesRemaining*8;
}
}
}
if (bitsToSeek > 0) {
if (!drflac__reload_cache(bs)) {
return DR_FALSE;
}
return drflac__seek_bits(bs, bitsToSeek);
}
return DR_TRUE;
}
}
static dr_bool32 drflac__read_uint32(drflac_bs* bs, unsigned int bitCount, uint32_t* pResultOut)
{
assert(bs != NULL);
assert(pResultOut != NULL);
assert(bitCount > 0);
assert(bitCount <= 32);
if (bs->consumedBits == DRFLAC_CACHE_L1_SIZE_BITS(bs)) {
if (!drflac__reload_cache(bs)) {
return DR_FALSE;
}
}
if (bitCount <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
if (bitCount < DRFLAC_CACHE_L1_SIZE_BITS(bs)) {
*pResultOut = DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCount);
bs->consumedBits += bitCount;
bs->cache <<= bitCount;
} else {
*pResultOut = (uint32_t)bs->cache;
bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs);
bs->cache = 0;
}
return DR_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.