-
Notifications
You must be signed in to change notification settings - Fork 19
/
dr_wav.h
3559 lines (2930 loc) · 129 KB
/
dr_wav.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
// WAV audio loader and writer. Public domain. See "unlicense" statement at the end of this file.
// dr_wav - v0.7f - 2018-02-05
//
// David Reid - [email protected]
// 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.totalSampleCount * sizeof(drwav_int32));
// size_t numberOfSamplesActuallyDecoded = drwav_read_s32(&wav, wav.totalSampleCount, 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 totalSampleCount;
// float* pSampleData = drwav_open_and_read_file_s32("my_song.wav", &channels, &sampleRate, &totalSampleCount);
// 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 it's internal format (see notes below for supported formats):
//
// size_t samplesRead = drwav_read(&wav, wav.totalSampleCount, 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 has seamless support the Sony Wave64 format. The decoder will automatically detect it and it should Just Work
// without any manual intervention.
//
//
// 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() 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(pWav, sampleCount, pSamples);
//
//
//
// OPTIONS
// #define these options before including this file.
//
// #define DR_WAV_NO_CONVERSION_API
// Disables conversion APIs such as drwav_read_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_f32() to read and convert audio data
// to IEEE 32-bit floating point samples, drwav_read_s32() to read samples as signed 32-bit PCM and drwav_read_s16()
// to read samples as signed 16-bit PCM. 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
#include <stddef.h>
#if defined(_MSC_VER) && _MSC_VER < 1600
typedef signed char drwav_int8;
typedef unsigned char drwav_uint8;
typedef signed short drwav_int16;
typedef unsigned short drwav_uint16;
typedef signed int drwav_int32;
typedef unsigned int drwav_uint32;
typedef signed __int64 drwav_int64;
typedef unsigned __int64 drwav_uint64;
#else
#include <stdint.h>
typedef int8_t drwav_int8;
typedef uint8_t drwav_uint8;
typedef int16_t drwav_int16;
typedef uint16_t drwav_uint16;
typedef int32_t drwav_int32;
typedef uint32_t drwav_uint32;
typedef int64_t drwav_int64;
typedef uint64_t drwav_uint64;
#endif
typedef drwav_uint8 drwav_bool8;
typedef drwav_uint32 drwav_bool32;
#define DRWAV_TRUE 1
#define DRWAV_FALSE 0
#ifdef __cplusplus
extern "C" {
#endif
// Common data formats.
#define DR_WAVE_FORMAT_PCM 0x1
#define DR_WAVE_FORMAT_ADPCM 0x2
#define DR_WAVE_FORMAT_IEEE_FLOAT 0x3
#define DR_WAVE_FORMAT_ALAW 0x6
#define DR_WAVE_FORMAT_MULAW 0x7
#define DR_WAVE_FORMAT_DVI_ADPCM 0x11
#define DR_WAVE_FORMAT_EXTENSIBLE 0xFFFE
typedef enum
{
drwav_seek_origin_start,
drwav_seek_origin_current
} drwav_seek_origin;
typedef enum
{
drwav_container_riff,
drwav_container_w64
} drwav_container;
// 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.
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.
typedef drwav_bool32 (* drwav_seek_proc)(void* pUserData, int offset, drwav_seek_origin origin);
// Structure for internal use. Only used for loaders opened with drwav_open_memory().
typedef struct
{
const drwav_uint8* data;
size_t dataSize;
size_t currentReadPos;
} drwav__memory_stream;
// Structure for internal use. Only used for writers opened with drwav_open_memory_write().
typedef struct
{
void** ppData;
size_t* pDataSize;
size_t dataSize;
size_t dataCapacity;
size_t currentWritePos;
} drwav__memory_stream_write;
typedef struct
{
drwav_container container; // RIFF, W64.
drwav_uint32 format; // DR_WAVE_FORMAT_*
drwav_uint32 channels;
drwav_uint32 sampleRate;
drwav_uint32 bitsPerSample;
} drwav_data_format;
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.
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.
drwav_uint16 channels;
// 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.
drwav_uint32 avgBytesPerSec;
// Block align. This is equal to the number of channels * bytes per sample.
drwav_uint16 blockAlign;
// Bit's per sample.
drwav_uint16 bitsPerSample;
// 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 <formatTag> is equal to WAVE_FORMAT_EXTENSIBLE, <bitsPerSample>
// 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.
drwav_uint32 channelMask;
// The sub-format, exactly as specified by the wave file.
drwav_uint8 subFormat[16];
} drwav_fmt;
typedef struct
{
// 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.
drwav_write_proc onWrite;
// 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.
void* pUserData;
// 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.
drwav_fmt fmt;
// 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.
drwav_uint16 channels;
// The bits per sample. Will be set to somthing like 16, 24, etc.
drwav_uint16 bitsPerSample;
// The number of bytes per sample.
drwav_uint16 bytesPerSample;
// 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 samples making up the audio data. Use <totalSampleCount> * <bytesPerSample> to calculate
// the required size of a buffer to hold the entire audio data.
drwav_uint64 totalSampleCount;
// 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.
drwav_uint64 dataChunkDataPos;
// The number of bytes remaining in the data chunk.
drwav_uint64 bytesRemaining;
// 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.
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.
} compressed;
// 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_uint32 cachedSampleCount;
drwav_int32 prevSamples[2][2]; // The previous 2 samples for each channel (2 channels at most).
} msadpcm;
// 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_uint32 cachedSampleCount;
} ima;
} drwav;
// Initializes a pre-allocated drwav object.
//
// 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 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.
//
// 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);
// 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 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);
// 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().
//
// This is the lowest level function for opening a WAV file. 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_open_file(), drwav_open_memory(), drwav_close()
drwav* drwav_open(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData);
// 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().
//
// This is the lowest level function for opening a WAV file. 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);
// 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_s16(), drwav_read_s32() or drwav_read_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 <samplesToRead> 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_s16/s32/f32/etc().
drwav_uint64 drwav_read(drwav* pWav, drwav_uint64 samplesToRead, void* pBufferOut);
// Seeks to the given sample.
//
// Returns true if successful; false otherwise.
drwav_bool32 drwav_seek_to_sample(drwav* pWav, drwav_uint64 sample);
// 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 audio data based on sample counts.
//
// Returns the number of samples written.
drwav_uint64 drwav_write(drwav* pWav, drwav_uint64 samplesToWrite, const void* pData);
//// Convertion 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 samples actually read.
//
// If the return value is less than <samplesToRead> it means the end of the file has been reached.
drwav_uint64 drwav_read_s16(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut);
// 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.
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.
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.
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.
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.
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.
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.
//
// Returns the number of samples actually read.
//
// If the return value is less than <samplesToRead> it means the end of the file has been reached.
drwav_uint64 drwav_read_f32(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut);
// 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.
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.
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.
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.
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.
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.
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.
//
// Returns the number of samples actually read.
//
// If the return value is less than <samplesToRead> it means the end of the file has been reached.
drwav_uint64 drwav_read_s32(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut);
// 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.
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.
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.
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.
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.
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.
void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
#endif //DR_WAV_NO_CONVERSION_API
//// High-Level Convenience Helpers ////
#ifndef DR_WAV_NO_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.
drwav_bool32 drwav_init_file(drwav* pWav, const char* filename);
// 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);
// 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);
// 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);
#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.
drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize);
// 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);
// 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);
// 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);
#ifndef DR_WAV_NO_CONVERSION_API
// Opens and reads a wav file in a single operation.
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);
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);
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);
#ifndef DR_WAV_NO_STDIO
// Opens and decodes a wav file in a single operation.
drwav_int16* drwav_open_and_read_file_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount);
float* drwav_open_and_read_file_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount);
drwav_int32* drwav_open_and_read_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount);
#endif
// Opens and decodes a wav file from a block of memory in a single operation.
drwav_int16* drwav_open_and_read_memory_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount);
float* drwav_open_and_read_memory_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount);
drwav_int32* drwav_open_and_read_memory_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount);
#endif
// Frees data that was allocated internally by dr_wav.
void drwav_free(void* pDataReturnedByOpenAndRead);
#ifdef __cplusplus
}
#endif
#endif // dr_wav_h
/////////////////////////////////////////////////////
//
// IMPLEMENTATION
//
/////////////////////////////////////////////////////
#ifdef DR_WAV_IMPLEMENTATION
#include <stdlib.h>
#include <string.h> // For memcpy(), memset()
#include <limits.h> // For INT_MAX
#ifndef DR_WAV_NO_STDIO
#include <stdio.h>
#endif
// Standard library stuff.
#ifndef DRWAV_ASSERT
#include <assert.h>
#define DRWAV_ASSERT(expression) assert(expression)
#endif
#ifndef DRWAV_MALLOC
#define DRWAV_MALLOC(sz) malloc((sz))
#endif
#ifndef DRWAV_REALLOC
#define DRWAV_REALLOC(p, sz) realloc((p), (sz))
#endif
#ifndef DRWAV_FREE
#define DRWAV_FREE(p) free((p))
#endif
#ifndef DRWAV_COPY_MEMORY
#define DRWAV_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz))
#endif
#ifndef DRWAV_ZERO_MEMORY
#define DRWAV_ZERO_MEMORY(p, sz) memset((p), 0, (sz))
#endif
#define drwav_countof(x) (sizeof(x) / sizeof(x[0]))
#define drwav_align(x, a) ((((x) + (a) - 1) / (a)) * (a))
#define drwav_min(a, b) (((a) < (b)) ? (a) : (b))
#define drwav_max(a, b) (((a) > (b)) ? (a) : (b))
#define drwav_clamp(x, lo, hi) (drwav_max((lo), drwav_min((hi), (x))))
#define drwav_assert DRWAV_ASSERT
#define drwav_copy_memory DRWAV_COPY_MEMORY
#define drwav_zero_memory DRWAV_ZERO_MEMORY
#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))
#else
#define DRWAV_INLINE inline
#endif
#endif
// I couldn't figure out where SIZE_MAX was defined for VC6. If anybody knows, let me know.
#if defined(_MSC_VER) && _MSC_VER <= 1200
#if defined(_WIN64)
#define SIZE_MAX ((drwav_uint64)0xFFFFFFFFFFFFFFFF)
#else
#define SIZE_MAX 0xFFFFFFFF
#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 DRWAV_INLINE drwav_bool32 drwav__guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16])
{
const drwav_uint32* a32 = (const drwav_uint32*)a;
const drwav_uint32* b32 = (const drwav_uint32*)b;
return
a32[0] == b32[0] &&
a32[1] == b32[1] &&
a32[2] == b32[2] &&
a32[3] == b32[3];
}
static DRWAV_INLINE drwav_bool32 drwav__fourcc_equal(const unsigned char* a, const char* b)
{
return
a[0] == b[0] &&
a[1] == b[1] &&
a[2] == b[2] &&
a[3] == b[3];
}
static DRWAV_INLINE int drwav__is_little_endian()
{
int n = 1;
return (*(char*)&n) == 1;
}
static DRWAV_INLINE unsigned short drwav__bytes_to_u16(const unsigned char* data)
{
if (drwav__is_little_endian()) {
return (data[0] << 0) | (data[1] << 8);
} else {
return (data[1] << 0) | (data[0] << 8);
}
}
static DRWAV_INLINE short drwav__bytes_to_s16(const unsigned char* data)
{
return (short)drwav__bytes_to_u16(data);
}
static DRWAV_INLINE unsigned int drwav__bytes_to_u32(const unsigned char* data)
{
if (drwav__is_little_endian()) {
return (data[0] << 0) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
} else {
return (data[3] << 0) | (data[2] << 8) | (data[1] << 16) | (data[0] << 24);
}
}
static DRWAV_INLINE drwav_uint64 drwav__bytes_to_u64(const unsigned char* data)
{
if (drwav__is_little_endian()) {
return
((drwav_uint64)data[0] << 0) | ((drwav_uint64)data[1] << 8) | ((drwav_uint64)data[2] << 16) | ((drwav_uint64)data[3] << 24) |
((drwav_uint64)data[4] << 32) | ((drwav_uint64)data[5] << 40) | ((drwav_uint64)data[6] << 48) | ((drwav_uint64)data[7] << 56);
} else {
return
((drwav_uint64)data[7] << 0) | ((drwav_uint64)data[6] << 8) | ((drwav_uint64)data[5] << 16) | ((drwav_uint64)data[4] << 24) |
((drwav_uint64)data[3] << 32) | ((drwav_uint64)data[2] << 40) | ((drwav_uint64)data[1] << 48) | ((drwav_uint64)data[0] << 56);
}
}
static DRWAV_INLINE void drwav__bytes_to_guid(const unsigned char* data, drwav_uint8* guid)
{
for (int i = 0; i < 16; ++i) {
guid[i] = data[i];
}
}
static DRWAV_INLINE drwav_bool32 drwav__is_compressed_format_tag(drwav_uint16 formatTag)
{
return
formatTag == DR_WAVE_FORMAT_ADPCM ||
formatTag == DR_WAVE_FORMAT_DVI_ADPCM;
}
drwav_uint64 drwav_read_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut);
drwav_uint64 drwav_read_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut);
typedef struct
{
union
{
drwav_uint8 fourcc[4];
drwav_uint8 guid[16];
} id;
// The size in bytes of the chunk.
drwav_uint64 sizeInBytes;
// RIFF = 2 byte alignment.
// W64 = 8 byte alignment.
unsigned int paddingSize;
} drwav__chunk_header;
static drwav_bool32 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) {
if (onRead(pUserData, pHeaderOut->id.fourcc, 4) != 4) {
return DRWAV_FALSE;
}
unsigned char sizeInBytes[4];
if (onRead(pUserData, sizeInBytes, 4) != 4) {
return DRWAV_FALSE;
}
pHeaderOut->sizeInBytes = drwav__bytes_to_u32(sizeInBytes);
pHeaderOut->paddingSize = (unsigned int)(pHeaderOut->sizeInBytes % 2);
*pRunningBytesReadOut += 8;
} else {
if (onRead(pUserData, pHeaderOut->id.guid, 16) != 16) {
return DRWAV_FALSE;
}
unsigned char sizeInBytes[8];
if (onRead(pUserData, sizeInBytes, 8) != 8) {
return DRWAV_FALSE;
}
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;
}
return DRWAV_TRUE;
}
static drwav_bool32 drwav__seek_forward(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData)
{
drwav_uint64 bytesRemainingToSeek = offset;
while (bytesRemainingToSeek > 0) {
if (bytesRemainingToSeek > 0x7FFFFFFF) {
if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) {
return DRWAV_FALSE;
}
bytesRemainingToSeek -= 0x7FFFFFFF;
} else {
if (!onSeek(pUserData, (int)bytesRemainingToSeek, drwav_seek_origin_current)) {
return DRWAV_FALSE;
}
bytesRemainingToSeek = 0;
}
}
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;
if (!drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header)) {
return DRWAV_FALSE;
}
// Skip junk chunks.
if ((container == drwav_container_riff && drwav__fourcc_equal(header.id.fourcc, "JUNK")) || (container == drwav_container_w64 && drwav__guid_equal(header.id.guid, drwavGUID_W64_JUNK))) {
if (!drwav__seek_forward(onSeek, header.sizeInBytes + header.paddingSize, pUserData)) {
return DRWAV_FALSE;
}
*pRunningBytesReadOut += header.sizeInBytes + header.paddingSize;
return drwav__read_fmt(onRead, onSeek, pUserData, container, pRunningBytesReadOut, fmtOut);
}
// Validation.
if (container == drwav_container_riff) {
if (!drwav__fourcc_equal(header.id.fourcc, "fmt ")) {
return DRWAV_FALSE;
}
} else {
if (!drwav__guid_equal(header.id.guid, drwavGUID_W64_FMT)) {
return DRWAV_FALSE;
}
}
unsigned char fmt[16];
if (onRead(pUserData, fmt, sizeof(fmt)) != sizeof(fmt)) {
return DRWAV_FALSE;
}
*pRunningBytesReadOut += sizeof(fmt);
fmtOut->formatTag = drwav__bytes_to_u16(fmt + 0);
fmtOut->channels = drwav__bytes_to_u16(fmt + 2);
fmtOut->sampleRate = drwav__bytes_to_u32(fmt + 4);
fmtOut->avgBytesPerSec = drwav__bytes_to_u32(fmt + 8);
fmtOut->blockAlign = drwav__bytes_to_u16(fmt + 12);
fmtOut->bitsPerSample = drwav__bytes_to_u16(fmt + 14);
fmtOut->extendedSize = 0;
fmtOut->validBitsPerSample = 0;
fmtOut->channelMask = 0;
memset(fmtOut->subFormat, 0, sizeof(fmtOut->subFormat));
if (header.sizeInBytes > 16) {
unsigned char fmt_cbSize[2];
if (onRead(pUserData, fmt_cbSize, sizeof(fmt_cbSize)) != sizeof(fmt_cbSize)) {
return DRWAV_FALSE; // Expecting more data.
}
*pRunningBytesReadOut += sizeof(fmt_cbSize);
int bytesReadSoFar = 18;
fmtOut->extendedSize = drwav__bytes_to_u16(fmt_cbSize);
if (fmtOut->extendedSize > 0) {
// Simple validation.
if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
if (fmtOut->extendedSize != 22) {
return DRWAV_FALSE;
}
}
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.
}
fmtOut->validBitsPerSample = drwav__bytes_to_u16(fmtext + 0);
fmtOut->channelMask = drwav__bytes_to_u32(fmtext + 2);
drwav__bytes_to_guid(fmtext + 6, fmtOut->subFormat);
} else {
if (!onSeek(pUserData, fmtOut->extendedSize, drwav_seek_origin_current)) {
return DRWAV_FALSE;
}
}
*pRunningBytesReadOut += fmtOut->extendedSize;
bytesReadSoFar += fmtOut->extendedSize;
}
// 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;
}
*pRunningBytesReadOut += (header.sizeInBytes - bytesReadSoFar);
}
if (header.paddingSize > 0) {
if (!onSeek(pUserData, header.paddingSize, drwav_seek_origin_current)) {
return DRWAV_FALSE;
}
*pRunningBytesReadOut += header.paddingSize;
}
return DRWAV_TRUE;
}