-
-
Notifications
You must be signed in to change notification settings - Fork 205
/
dr_wav.h
8815 lines (7178 loc) · 344 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. Choice of public domain or MIT-0. See license statements at the end of this file.
dr_wav - v0.13.16 - 2024-02-27
David Reid - [email protected]
GitHub: https://github.com/mackron/dr_libs
*/
/*
Introduction
============
This is a single file library. To use it, do something like the following in one .c file.
```c
#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:
```c
drwav wav;
if (!drwav_init_file(&wav, "my_song.wav", NULL)) {
// Error opening WAV file.
}
drwav_int32* pDecodedInterleavedPCMFrames = malloc(wav.totalPCMFrameCount * wav.channels * sizeof(drwav_int32));
size_t numberOfSamplesActuallyDecoded = drwav_read_pcm_frames_s32(&wav, wav.totalPCMFrameCount, pDecodedInterleavedPCMFrames);
...
drwav_uninit(&wav);
```
If you just want to quickly open and read the audio data in a single operation you can do something like this:
```c
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, NULL);
if (pSampleData == NULL) {
// Error opening and reading WAV file.
}
...
drwav_free(pSampleData, NULL);
```
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):
```c
size_t framesRead = drwav_read_pcm_frames(&wav, wav.totalPCMFrameCount, pDecodedInterleavedPCMFrames);
```
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:
```c
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_init_write()`,
`drwav_init_file_write()`, etc. Use `drwav_write_pcm_frames()` to write samples, or `drwav_write_raw()` to write raw data in the "data" chunk.
```c
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_init_file_write(&wav, "data/recording.wav", &format, NULL);
...
drwav_uint64 framesWritten = drwav_write_pcm_frames(pWav, frameCount, pSamples);
```
Note that writing to AIFF or RIFX is not supported.
dr_wav has support for decoding from a number of different encapsulation formats. See below for details.
Build 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 APIs that initialize a decoder from a file such as `drwav_init_file()`, `drwav_init_file_write()`, etc.
#define DR_WAV_NO_WCHAR
Disables all functions ending with `_w`. Use this if your compiler does not provide wchar.h. Not required if DR_WAV_NO_STDIO is also defined.
Supported Encapsulations
========================
- RIFF (Regular WAV)
- RIFX (Big-Endian)
- AIFF (Does not currently support ADPCM)
- RF64
- W64
Note that AIFF and RIFX do not support write mode, nor do they support reading of metadata.
Supported Encodings
===================
- 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)
8-bit PCM encodings are always assumed to be unsigned. Signed 8-bit encoding can only be read with `drwav_read_raw()`.
Note that ADPCM is not currently supported with AIFF. Contributions welcome.
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.
- 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
#ifdef __cplusplus
extern "C" {
#endif
#define DRWAV_STRINGIFY(x) #x
#define DRWAV_XSTRINGIFY(x) DRWAV_STRINGIFY(x)
#define DRWAV_VERSION_MAJOR 0
#define DRWAV_VERSION_MINOR 13
#define DRWAV_VERSION_REVISION 16
#define DRWAV_VERSION_STRING DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION)
#include <stddef.h> /* For size_t. */
/* Sized Types */
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;
#if defined(_MSC_VER) && !defined(__clang__)
typedef signed __int64 drwav_int64;
typedef unsigned __int64 drwav_uint64;
#else
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlong-long"
#if defined(__clang__)
#pragma GCC diagnostic ignored "-Wc++11-long-long"
#endif
#endif
typedef signed long long drwav_int64;
typedef unsigned long long drwav_uint64;
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
#pragma GCC diagnostic pop
#endif
#endif
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__)
typedef drwav_uint64 drwav_uintptr;
#else
typedef drwav_uint32 drwav_uintptr;
#endif
typedef drwav_uint8 drwav_bool8;
typedef drwav_uint32 drwav_bool32;
#define DRWAV_TRUE 1
#define DRWAV_FALSE 0
/* End Sized Types */
/* Decorations */
#if !defined(DRWAV_API)
#if defined(DRWAV_DLL)
#if defined(_WIN32)
#define DRWAV_DLL_IMPORT __declspec(dllimport)
#define DRWAV_DLL_EXPORT __declspec(dllexport)
#define DRWAV_DLL_PRIVATE static
#else
#if defined(__GNUC__) && __GNUC__ >= 4
#define DRWAV_DLL_IMPORT __attribute__((visibility("default")))
#define DRWAV_DLL_EXPORT __attribute__((visibility("default")))
#define DRWAV_DLL_PRIVATE __attribute__((visibility("hidden")))
#else
#define DRWAV_DLL_IMPORT
#define DRWAV_DLL_EXPORT
#define DRWAV_DLL_PRIVATE static
#endif
#endif
#if defined(DR_WAV_IMPLEMENTATION) || defined(DRWAV_IMPLEMENTATION)
#define DRWAV_API DRWAV_DLL_EXPORT
#else
#define DRWAV_API DRWAV_DLL_IMPORT
#endif
#define DRWAV_PRIVATE DRWAV_DLL_PRIVATE
#else
#define DRWAV_API extern
#define DRWAV_PRIVATE static
#endif
#endif
/* End Decorations */
/* Result Codes */
typedef drwav_int32 drwav_result;
#define DRWAV_SUCCESS 0
#define DRWAV_ERROR -1 /* A generic error. */
#define DRWAV_INVALID_ARGS -2
#define DRWAV_INVALID_OPERATION -3
#define DRWAV_OUT_OF_MEMORY -4
#define DRWAV_OUT_OF_RANGE -5
#define DRWAV_ACCESS_DENIED -6
#define DRWAV_DOES_NOT_EXIST -7
#define DRWAV_ALREADY_EXISTS -8
#define DRWAV_TOO_MANY_OPEN_FILES -9
#define DRWAV_INVALID_FILE -10
#define DRWAV_TOO_BIG -11
#define DRWAV_PATH_TOO_LONG -12
#define DRWAV_NAME_TOO_LONG -13
#define DRWAV_NOT_DIRECTORY -14
#define DRWAV_IS_DIRECTORY -15
#define DRWAV_DIRECTORY_NOT_EMPTY -16
#define DRWAV_END_OF_FILE -17
#define DRWAV_NO_SPACE -18
#define DRWAV_BUSY -19
#define DRWAV_IO_ERROR -20
#define DRWAV_INTERRUPT -21
#define DRWAV_UNAVAILABLE -22
#define DRWAV_ALREADY_IN_USE -23
#define DRWAV_BAD_ADDRESS -24
#define DRWAV_BAD_SEEK -25
#define DRWAV_BAD_PIPE -26
#define DRWAV_DEADLOCK -27
#define DRWAV_TOO_MANY_LINKS -28
#define DRWAV_NOT_IMPLEMENTED -29
#define DRWAV_NO_MESSAGE -30
#define DRWAV_BAD_MESSAGE -31
#define DRWAV_NO_DATA_AVAILABLE -32
#define DRWAV_INVALID_DATA -33
#define DRWAV_TIMEOUT -34
#define DRWAV_NO_NETWORK -35
#define DRWAV_NOT_UNIQUE -36
#define DRWAV_NOT_SOCKET -37
#define DRWAV_NO_ADDRESS -38
#define DRWAV_BAD_PROTOCOL -39
#define DRWAV_PROTOCOL_UNAVAILABLE -40
#define DRWAV_PROTOCOL_NOT_SUPPORTED -41
#define DRWAV_PROTOCOL_FAMILY_NOT_SUPPORTED -42
#define DRWAV_ADDRESS_FAMILY_NOT_SUPPORTED -43
#define DRWAV_SOCKET_NOT_SUPPORTED -44
#define DRWAV_CONNECTION_RESET -45
#define DRWAV_ALREADY_CONNECTED -46
#define DRWAV_NOT_CONNECTED -47
#define DRWAV_CONNECTION_REFUSED -48
#define DRWAV_NO_HOST -49
#define DRWAV_IN_PROGRESS -50
#define DRWAV_CANCELLED -51
#define DRWAV_MEMORY_ALREADY_MAPPED -52
#define DRWAV_AT_END -53
/* End Result Codes */
/* 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
/* Flags to pass into drwav_init_ex(), etc. */
#define DRWAV_SEQUENTIAL 0x00000001
#define DRWAV_WITH_METADATA 0x00000002
DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision);
DRWAV_API const char* drwav_version_string(void);
/* Allocation Callbacks */
typedef struct
{
void* pUserData;
void* (* onMalloc)(size_t sz, void* pUserData);
void* (* onRealloc)(void* p, size_t sz, void* pUserData);
void (* onFree)(void* p, void* pUserData);
} drwav_allocation_callbacks;
/* End Allocation Callbacks */
typedef enum
{
drwav_seek_origin_start,
drwav_seek_origin_current
} drwav_seek_origin;
typedef enum
{
drwav_container_riff,
drwav_container_rifx,
drwav_container_w64,
drwav_container_rf64,
drwav_container_aiff
} drwav_container;
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;
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;
/* Bits 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 are 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;
DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT);
/*
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() 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() 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() 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() finds a chunk.
pChunkUserData [in] The user data that was passed to the pChunkUserData parameter of drwav_init_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() and family.
pChunkHeader [in] A pointer to an object containing basic header information about the chunk. Use this to identify the chunk.
container [in] Whether or not the WAV file is a RIFF or Wave64 container. If you're unsure of the difference, assume RIFF.
pFMT [in] A pointer to the object containing the contents of the "fmt" 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.
Use the `container` argument to discriminate the fields in `pChunkHeader->id`. If the container is `drwav_container_riff` or `drwav_container_rf64` you should
use `id.fourcc`, otherwise you should use `id.guid`.
The `pFMT` parameter can be used to determine the data format of the wave file. Use `drwav_fmt_get_format()` to get the sample format, which will be one of the
`DR_WAVE_FORMAT_*` identifiers.
The read pointer will be sitting on the first byte after the chunk's header. 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, drwav_container container, const drwav_fmt* pFMT);
/* Structure for internal use. Only used for loaders opened with drwav_init_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_init_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 enum
{
drwav_metadata_type_none = 0,
/*
Unknown simply means a chunk that drwav does not handle specifically. You can still ask to
receive these chunks as metadata objects. It is then up to you to interpret the chunk's data.
You can also write unknown metadata to a wav file. Be careful writing unknown chunks if you
have also edited the audio data. The unknown chunks could represent offsets/sizes that no
longer correctly correspond to the audio data.
*/
drwav_metadata_type_unknown = 1 << 0,
/* Only 1 of each of these metadata items are allowed in a wav file. */
drwav_metadata_type_smpl = 1 << 1,
drwav_metadata_type_inst = 1 << 2,
drwav_metadata_type_cue = 1 << 3,
drwav_metadata_type_acid = 1 << 4,
drwav_metadata_type_bext = 1 << 5,
/*
Wav files often have a LIST chunk. This is a chunk that contains a set of subchunks. For this
higher-level metadata API, we don't make a distinction between a regular chunk and a LIST
subchunk. Instead, they are all just 'metadata' items.
There can be multiple of these metadata items in a wav file.
*/
drwav_metadata_type_list_label = 1 << 6,
drwav_metadata_type_list_note = 1 << 7,
drwav_metadata_type_list_labelled_cue_region = 1 << 8,
drwav_metadata_type_list_info_software = 1 << 9,
drwav_metadata_type_list_info_copyright = 1 << 10,
drwav_metadata_type_list_info_title = 1 << 11,
drwav_metadata_type_list_info_artist = 1 << 12,
drwav_metadata_type_list_info_comment = 1 << 13,
drwav_metadata_type_list_info_date = 1 << 14,
drwav_metadata_type_list_info_genre = 1 << 15,
drwav_metadata_type_list_info_album = 1 << 16,
drwav_metadata_type_list_info_tracknumber = 1 << 17,
/* Other type constants for convenience. */
drwav_metadata_type_list_all_info_strings = drwav_metadata_type_list_info_software
| drwav_metadata_type_list_info_copyright
| drwav_metadata_type_list_info_title
| drwav_metadata_type_list_info_artist
| drwav_metadata_type_list_info_comment
| drwav_metadata_type_list_info_date
| drwav_metadata_type_list_info_genre
| drwav_metadata_type_list_info_album
| drwav_metadata_type_list_info_tracknumber,
drwav_metadata_type_list_all_adtl = drwav_metadata_type_list_label
| drwav_metadata_type_list_note
| drwav_metadata_type_list_labelled_cue_region,
drwav_metadata_type_all = -2, /*0xFFFFFFFF & ~drwav_metadata_type_unknown,*/
drwav_metadata_type_all_including_unknown = -1 /*0xFFFFFFFF,*/
} drwav_metadata_type;
/*
Sampler Metadata
The sampler chunk contains information about how a sound should be played in the context of a whole
audio production, and when used in a sampler. See https://en.wikipedia.org/wiki/Sample-based_synthesis.
*/
typedef enum
{
drwav_smpl_loop_type_forward = 0,
drwav_smpl_loop_type_pingpong = 1,
drwav_smpl_loop_type_backward = 2
} drwav_smpl_loop_type;
typedef struct
{
/* The ID of the associated cue point, see drwav_cue and drwav_cue_point. As with all cue point IDs, this can correspond to a label chunk to give this loop a name, see drwav_list_label_or_note. */
drwav_uint32 cuePointId;
/* See drwav_smpl_loop_type. */
drwav_uint32 type;
/* The byte offset of the first sample to be played in the loop. */
drwav_uint32 firstSampleByteOffset;
/* The byte offset into the audio data of the last sample to be played in the loop. */
drwav_uint32 lastSampleByteOffset;
/* A value to represent that playback should occur at a point between samples. This value ranges from 0 to UINT32_MAX. Where a value of 0 means no fraction, and a value of (UINT32_MAX / 2) would mean half a sample. */
drwav_uint32 sampleFraction;
/* Number of times to play the loop. 0 means loop infinitely. */
drwav_uint32 playCount;
} drwav_smpl_loop;
typedef struct
{
/* IDs for a particular MIDI manufacturer. 0 if not used. */
drwav_uint32 manufacturerId;
drwav_uint32 productId;
/* The period of 1 sample in nanoseconds. */
drwav_uint32 samplePeriodNanoseconds;
/* The MIDI root note of this file. 0 to 127. */
drwav_uint32 midiUnityNote;
/* The fraction of a semitone up from the given MIDI note. This is a value from 0 to UINT32_MAX, where 0 means no change and (UINT32_MAX / 2) is half a semitone (AKA 50 cents). */
drwav_uint32 midiPitchFraction;
/* Data relating to SMPTE standards which are used for syncing audio and video. 0 if not used. */
drwav_uint32 smpteFormat;
drwav_uint32 smpteOffset;
/* drwav_smpl_loop loops. */
drwav_uint32 sampleLoopCount;
/* Optional sampler-specific data. */
drwav_uint32 samplerSpecificDataSizeInBytes;
drwav_smpl_loop* pLoops;
drwav_uint8* pSamplerSpecificData;
} drwav_smpl;
/*
Instrument Metadata
The inst metadata contains data about how a sound should be played as part of an instrument. This
commonly read by samplers. See https://en.wikipedia.org/wiki/Sample-based_synthesis.
*/
typedef struct
{
drwav_int8 midiUnityNote; /* The root note of the audio as a MIDI note number. 0 to 127. */
drwav_int8 fineTuneCents; /* -50 to +50 */
drwav_int8 gainDecibels; /* -64 to +64 */
drwav_int8 lowNote; /* 0 to 127 */
drwav_int8 highNote; /* 0 to 127 */
drwav_int8 lowVelocity; /* 1 to 127 */
drwav_int8 highVelocity; /* 1 to 127 */
} drwav_inst;
/*
Cue Metadata
Cue points are markers at specific points in the audio. They often come with an associated piece of
drwav_list_label_or_note metadata which contains the text for the marker.
*/
typedef struct
{
/* Unique identification value. */
drwav_uint32 id;
/* Set to 0. This is only relevant if there is a 'playlist' chunk - which is not supported by dr_wav. */
drwav_uint32 playOrderPosition;
/* Should always be "data". This represents the fourcc value of the chunk that this cue point corresponds to. dr_wav only supports a single data chunk so this should always be "data". */
drwav_uint8 dataChunkId[4];
/* Set to 0. This is only relevant if there is a wave list chunk. dr_wav, like lots of readers/writers, do not support this. */
drwav_uint32 chunkStart;
/* Set to 0 for uncompressed formats. Else the last byte in compressed wave data where decompression can begin to find the value of the corresponding sample value. */
drwav_uint32 blockStart;
/* For uncompressed formats this is the byte offset of the cue point into the audio data. For compressed formats this is relative to the block specified with blockStart. */
drwav_uint32 sampleByteOffset;
} drwav_cue_point;
typedef struct
{
drwav_uint32 cuePointCount;
drwav_cue_point *pCuePoints;
} drwav_cue;
/*
Acid Metadata
This chunk contains some information about the time signature and the tempo of the audio.
*/
typedef enum
{
drwav_acid_flag_one_shot = 1, /* If this is not set, then it is a loop instead of a one-shot. */
drwav_acid_flag_root_note_set = 2,
drwav_acid_flag_stretch = 4,
drwav_acid_flag_disk_based = 8,
drwav_acid_flag_acidizer = 16 /* Not sure what this means. */
} drwav_acid_flag;
typedef struct
{
/* A bit-field, see drwav_acid_flag. */
drwav_uint32 flags;
/* Valid if flags contains drwav_acid_flag_root_note_set. It represents the MIDI root note the file - a value from 0 to 127. */
drwav_uint16 midiUnityNote;
/* Reserved values that should probably be ignored. reserved1 seems to often be 128 and reserved2 is 0. */
drwav_uint16 reserved1;
float reserved2;
/* Number of beats. */
drwav_uint32 numBeats;
/* The time signature of the audio. */
drwav_uint16 meterDenominator;
drwav_uint16 meterNumerator;
/* Beats per minute of the track. Setting a value of 0 suggests that there is no tempo. */
float tempo;
} drwav_acid;
/*
Cue Label or Note metadata
These are 2 different types of metadata, but they have the exact same format. Labels tend to be the
more common and represent a short name for a cue point. Notes might be used to represent a longer
comment.
*/
typedef struct
{
/* The ID of a cue point that this label or note corresponds to. */
drwav_uint32 cuePointId;
/* Size of the string not including any null terminator. */
drwav_uint32 stringLength;
/* The string. The *init_with_metadata functions null terminate this for convenience. */
char* pString;
} drwav_list_label_or_note;
/*
BEXT metadata, also known as Broadcast Wave Format (BWF)
This metadata adds some extra description to an audio file. You must check the version field to
determine if the UMID or the loudness fields are valid.
*/
typedef struct
{
/*
These top 3 fields, and the umid field are actually defined in the standard as a statically
sized buffers. In order to reduce the size of this struct (and therefore the union in the
metadata struct), we instead store these as pointers.
*/
char* pDescription; /* Can be NULL or a null-terminated string, must be <= 256 characters. */
char* pOriginatorName; /* Can be NULL or a null-terminated string, must be <= 32 characters. */
char* pOriginatorReference; /* Can be NULL or a null-terminated string, must be <= 32 characters. */
char pOriginationDate[10]; /* ASCII "yyyy:mm:dd". */
char pOriginationTime[8]; /* ASCII "hh:mm:ss". */
drwav_uint64 timeReference; /* First sample count since midnight. */
drwav_uint16 version; /* Version of the BWF, check this to see if the fields below are valid. */
/*
Unrestricted ASCII characters containing a collection of strings terminated by CR/LF. Each
string shall contain a description of a coding process applied to the audio data.
*/
char* pCodingHistory;
drwav_uint32 codingHistorySize;
/* Fields below this point are only valid if the version is 1 or above. */
drwav_uint8* pUMID; /* Exactly 64 bytes of SMPTE UMID */
/* Fields below this point are only valid if the version is 2 or above. */
drwav_uint16 loudnessValue; /* Integrated Loudness Value of the file in LUFS (multiplied by 100). */
drwav_uint16 loudnessRange; /* Loudness Range of the file in LU (multiplied by 100). */
drwav_uint16 maxTruePeakLevel; /* Maximum True Peak Level of the file expressed as dBTP (multiplied by 100). */
drwav_uint16 maxMomentaryLoudness; /* Highest value of the Momentary Loudness Level of the file in LUFS (multiplied by 100). */
drwav_uint16 maxShortTermLoudness; /* Highest value of the Short-Term Loudness Level of the file in LUFS (multiplied by 100). */
} drwav_bext;
/*
Info Text Metadata
There a many different types of information text that can be saved in this format. This is where
things like the album name, the artists, the year it was produced, etc are saved. See
drwav_metadata_type for the full list of types that dr_wav supports.
*/
typedef struct
{
/* Size of the string not including any null terminator. */
drwav_uint32 stringLength;
/* The string. The *init_with_metadata functions null terminate this for convenience. */
char* pString;
} drwav_list_info_text;
/*
Labelled Cue Region Metadata
The labelled cue region metadata is used to associate some region of audio with text. The region
starts at a cue point, and extends for the given number of samples.
*/
typedef struct
{
/* The ID of a cue point that this object corresponds to. */
drwav_uint32 cuePointId;
/* The number of samples from the cue point forwards that should be considered this region */
drwav_uint32 sampleLength;
/* Four characters used to say what the purpose of this region is. */
drwav_uint8 purposeId[4];
/* Unsure of the exact meanings of these. It appears to be acceptable to set them all to 0. */
drwav_uint16 country;
drwav_uint16 language;
drwav_uint16 dialect;
drwav_uint16 codePage;
/* Size of the string not including any null terminator. */
drwav_uint32 stringLength;
/* The string. The *init_with_metadata functions null terminate this for convenience. */
char* pString;
} drwav_list_labelled_cue_region;
/*
Unknown Metadata
This chunk just represents a type of chunk that dr_wav does not understand.
Unknown metadata has a location attached to it. This is because wav files can have a LIST chunk
that contains subchunks. These LIST chunks can be one of two types. An adtl list, or an INFO
list. This enum is used to specify the location of a chunk that dr_wav currently doesn't support.
*/
typedef enum
{
drwav_metadata_location_invalid,
drwav_metadata_location_top_level,
drwav_metadata_location_inside_info_list,
drwav_metadata_location_inside_adtl_list
} drwav_metadata_location;
typedef struct
{
drwav_uint8 id[4];
drwav_metadata_location chunkLocation;
drwav_uint32 dataSizeInBytes;
drwav_uint8* pData;
} drwav_unknown_metadata;
/*
Metadata is saved as a union of all the supported types.
*/
typedef struct
{
/* Determines which item in the union is valid. */
drwav_metadata_type type;
union
{
drwav_cue cue;
drwav_smpl smpl;
drwav_acid acid;
drwav_inst inst;
drwav_bext bext;
drwav_list_label_or_note labelOrNote; /* List label or list note. */
drwav_list_labelled_cue_region labelledCueRegion;
drwav_list_info_text infoText; /* Any of the list info types. */
drwav_unknown_metadata unknown;
} data;
} drwav_metadata;
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;
/* Allocation callbacks. */
drwav_allocation_callbacks allocationCallbacks;
/* 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 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). */
drwav_uint16 translatedFormatTag;
/* The total number of PCM frames making up the audio data. */
drwav_uint64 totalPCMFrameCount;
/* The size in bytes of the data chunk. */
drwav_uint64 dataChunkDataSize;
/* The position in the stream of the first data 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;
/* The current read position in PCM frames. */
drwav_uint64 readCursorInPCMFrames;
/*
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. */
drwav_bool32 isSequentialWrite;
/* A array of metadata. This is valid after the *init_with_metadata call returns. It will be valid until drwav_uninit() is called. You can take ownership of this data with drwav_take_ownership_of_metadata(). */
drwav_metadata* pMetadata;
drwav_uint32 metadataCount;
/* A hack to avoid a DRWAV_MALLOC() when opening a decoder with drwav_init_memory(). */
drwav__memory_stream memoryStream;
drwav__memory_stream_write memoryStreamWrite;
/* Microsoft ADPCM specific data. */
struct
{
drwav_uint32 bytesRemainingInBlock;
drwav_uint16 predictor[2];
drwav_int32 delta[2];
drwav_int32 cachedFrames[4]; /* Samples are stored in this cache during decoding. */
drwav_uint32 cachedFrameCount;
drwav_int32 prevFrames[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 cachedFrames[16]; /* Samples are stored in this cache during decoding. */
drwav_uint32 cachedFrameCount;
} ima;
/* AIFF specific data. */
struct
{
drwav_bool8 isLE; /* Will be set to true if the audio data is little-endian encoded. */
drwav_bool8 isUnsigned; /* Only used for 8-bit samples. When set to true, will be treated as unsigned. */
} aiff;
} drwav;
/*
Initializes a pre-allocated drwav object for reading.
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.
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_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API 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, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_bool32 drwav_init_with_metadata(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks);
/*
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.
metadata, numMetadata [in, optional] An array of metadata objects that should be written to the file. The array is not edited. You are responsible for this metadata memory and it must maintain valid until drwav_uninit() is called.
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_write() and drwav_init_memory_write()
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.
See also: drwav_init_file_write(), drwav_init_memory_write(), drwav_uninit()
*/
DRWAV_API drwav_bool32 drwav_init_write(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_bool32 drwav_init_write_sequential(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_bool32 drwav_init_write_sequential_pcm_frames(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks);
DRWAV_API drwav_bool32 drwav_init_write_with_metadata(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks, drwav_metadata* pMetadata, drwav_uint32 metadataCount);
/*