Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
miniaudio
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
miniaudio
Commits
be65f148
Commit
be65f148
authored
Nov 04, 2017
by
David Reid
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update dr_wav.
parent
b0000958
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
515 additions
and
9 deletions
+515
-9
extras/dr_wav.h
extras/dr_wav.h
+515
-9
No files found.
extras/dr_wav.h
View file @
be65f148
// WAV audio loader. Public domain. See "unlicense" statement at the end of this file.
// WAV audio loader
and writer
. Public domain. See "unlicense" statement at the end of this file.
// dr_wav - v0.
6 - 2017-08-16
// dr_wav - v0.
7 - 2017-11-04
//
//
// David Reid - mackron@gmail.com
// David Reid - mackron@gmail.com
...
@@ -64,6 +64,23 @@
...
@@ -64,6 +64,23 @@
// without any manual intervention.
// 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
// OPTIONS
// #define these options before including this file.
// #define these options before including this file.
...
@@ -72,7 +89,7 @@
...
@@ -72,7 +89,7 @@
// Disables conversion APIs such as drwav_read_f32() and drwav_s16_to_f32().
// Disables conversion APIs such as drwav_read_f32() and drwav_s16_to_f32().
//
//
// #define DR_WAV_NO_STDIO
// #define DR_WAV_NO_STDIO
// Disables drwav_open_file().
// Disables drwav_open_file()
, drwav_open_file_write(), etc
.
//
//
//
//
//
//
...
@@ -161,6 +178,17 @@ typedef enum
...
@@ -161,6 +178,17 @@ typedef enum
// either the entire bytesToRead is filled or you have reached the end of the stream.
// 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
);
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.
// Callback for when data needs to be seeked.
//
//
// pUserData [in] The user data that was passed to drwav_init(), drwav_open() and family.
// pUserData [in] The user data that was passed to drwav_init(), drwav_open() and family.
...
@@ -173,7 +201,7 @@ typedef size_t (* drwav_read_proc)(void* pUserData, void* pBufferOut, size_t byt
...
@@ -173,7 +201,7 @@ typedef size_t (* drwav_read_proc)(void* pUserData, void* pBufferOut, size_t byt
// will be either drwav_seek_origin_start or drwav_seek_origin_current.
// 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
);
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.
// Structure for internal use. Only used for loaders opened with drwav_open_memory
()
.
typedef
struct
typedef
struct
{
{
const
drwav_uint8
*
data
;
const
drwav_uint8
*
data
;
...
@@ -181,6 +209,25 @@ typedef struct
...
@@ -181,6 +209,25 @@ typedef struct
size_t
currentReadPos
;
size_t
currentReadPos
;
}
drwav__memory_stream
;
}
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
typedef
struct
{
{
// The format tag exactly as specified in the wave file's "fmt" chunk. This can be used by applications
// The format tag exactly as specified in the wave file's "fmt" chunk. This can be used by applications
...
@@ -222,6 +269,9 @@ typedef struct
...
@@ -222,6 +269,9 @@ typedef struct
// A pointer to the function to call when more data is needed.
// A pointer to the function to call when more data is needed.
drwav_read_proc
onRead
;
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.
// A pointer to the function to call when the wav file needs to be seeked.
drwav_seek_proc
onSeek
;
drwav_seek_proc
onSeek
;
...
@@ -268,7 +318,7 @@ typedef struct
...
@@ -268,7 +318,7 @@ typedef struct
// A hack to avoid a DRWAV_MALLOC() when opening a decoder with drwav_open_memory().
// A hack to avoid a DRWAV_MALLOC() when opening a decoder with drwav_open_memory().
drwav__memory_stream
memoryStream
;
drwav__memory_stream
memoryStream
;
drwav__memory_stream_write
memoryStreamWrite
;
// Generic data for compressed formats. This data is shared across all block-compressed formats.
// Generic data for compressed formats. This data is shared across all block-compressed formats.
struct
struct
...
@@ -318,6 +368,25 @@ typedef struct
...
@@ -318,6 +368,25 @@ typedef struct
// See also: drwav_init_file(), drwav_init_memory(), drwav_uninit()
// See also: drwav_init_file(), drwav_init_memory(), drwav_uninit()
drwav_bool32
drwav_init
(
drwav
*
pWav
,
drwav_read_proc
onRead
,
drwav_seek_proc
onSeek
,
void
*
pUserData
);
drwav_bool32
drwav_init
(
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.
// Uninitializes the given drwav object.
//
//
// Use this only for objects initialized with drwav_init().
// Use this only for objects initialized with drwav_init().
...
@@ -343,6 +412,25 @@ void drwav_uninit(drwav* pWav);
...
@@ -343,6 +412,25 @@ void drwav_uninit(drwav* pWav);
// See also: drwav_open_file(), drwav_open_memory(), drwav_close()
// See also: drwav_open_file(), drwav_open_memory(), drwav_close()
drwav
*
drwav_open
(
drwav_read_proc
onRead
,
drwav_seek_proc
onSeek
,
void
*
pUserData
);
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.
// Uninitializes and deletes the the given drwav object.
//
//
// Use this only for objects created with drwav_open().
// Use this only for objects created with drwav_open().
...
@@ -378,6 +466,17 @@ drwav_uint64 drwav_read(drwav* pWav, drwav_uint64 samplesToRead, void* pBufferOu
...
@@ -378,6 +466,17 @@ drwav_uint64 drwav_read(drwav* pWav, drwav_uint64 samplesToRead, void* pBufferOu
drwav_bool32
drwav_seek_to_sample
(
drwav
*
pWav
,
drwav_uint64
sample
);
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 ////
//// Convertion Utilities ////
#ifndef DR_WAV_NO_CONVERSION_API
#ifndef DR_WAV_NO_CONVERSION_API
...
@@ -482,6 +581,13 @@ void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sample
...
@@ -482,6 +581,13 @@ void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sample
// any given time.
// any given time.
drwav_bool32
drwav_init_file
(
drwav
*
pWav
,
const
char
*
filename
);
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.
// 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
// This holds the internal FILE object until drwav_close() is called. Keep this in mind if you're caching drwav
...
@@ -489,9 +595,16 @@ drwav_bool32 drwav_init_file(drwav* pWav, const char* filename);
...
@@ -489,9 +595,16 @@ drwav_bool32 drwav_init_file(drwav* pWav, const char* filename);
// any given time.
// any given time.
drwav
*
drwav_open_file
(
const
char
*
filename
);
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
#endif //DR_WAV_NO_STDIO
// Helper for initializing a
file
from a pre-allocated memory buffer.
// 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
// 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 lifetime of the drwav object.
...
@@ -499,7 +612,15 @@ drwav* drwav_open_file(const char* filename);
...
@@ -499,7 +612,15 @@ drwav* drwav_open_file(const char* filename);
// The buffer should contain the contents of the entire wave file, not just the sample data.
// The buffer should contain the contents of the entire wave file, not just the sample data.
drwav_bool32
drwav_init_memory
(
drwav
*
pWav
,
const
void
*
data
,
size_t
dataSize
);
drwav_bool32
drwav_init_memory
(
drwav
*
pWav
,
const
void
*
data
,
size_t
dataSize
);
// Helper for opening a file from a pre-allocated memory buffer.
// 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
// 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 lifetime of the drwav object.
...
@@ -507,6 +628,13 @@ drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize);
...
@@ -507,6 +628,13 @@ drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize);
// The buffer should contain the contents of the entire wave file, not just the sample data.
// The buffer should contain the contents of the entire wave file, not just the sample data.
drwav
*
drwav_open_memory
(
const
void
*
data
,
size_t
dataSize
);
drwav
*
drwav_open_memory
(
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
#ifndef DR_WAV_NO_CONVERSION_API
...
@@ -873,6 +1001,11 @@ static size_t drwav__on_read_stdio(void* pUserData, void* pBufferOut, size_t byt
...
@@ -873,6 +1001,11 @@ static size_t drwav__on_read_stdio(void* pUserData, void* pBufferOut, size_t byt
return
fread
(
pBufferOut
,
1
,
bytesToRead
,
(
FILE
*
)
pUserData
);
return
fread
(
pBufferOut
,
1
,
bytesToRead
,
(
FILE
*
)
pUserData
);
}
}
static
size_t
drwav__on_write_stdio
(
void
*
pUserData
,
const
void
*
pData
,
size_t
bytesToWrite
)
{
return
fwrite
(
pData
,
1
,
bytesToWrite
,
(
FILE
*
)
pUserData
);
}
static
drwav_bool32
drwav__on_seek_stdio
(
void
*
pUserData
,
int
offset
,
drwav_seek_origin
origin
)
static
drwav_bool32
drwav__on_seek_stdio
(
void
*
pUserData
,
int
offset
,
drwav_seek_origin
origin
)
{
{
return
fseek
((
FILE
*
)
pUserData
,
offset
,
(
origin
==
drwav_seek_origin_current
)
?
SEEK_CUR
:
SEEK_SET
)
==
0
;
return
fseek
((
FILE
*
)
pUserData
,
offset
,
(
origin
==
drwav_seek_origin_current
)
?
SEEK_CUR
:
SEEK_SET
)
==
0
;
...
@@ -895,6 +1028,23 @@ drwav_bool32 drwav_init_file(drwav* pWav, const char* filename)
...
@@ -895,6 +1028,23 @@ drwav_bool32 drwav_init_file(drwav* pWav, const char* filename)
return
drwav_init
(
pWav
,
drwav__on_read_stdio
,
drwav__on_seek_stdio
,
(
void
*
)
pFile
);
return
drwav_init
(
pWav
,
drwav__on_read_stdio
,
drwav__on_seek_stdio
,
(
void
*
)
pFile
);
}
}
drwav_bool32
drwav_init_file_write
(
drwav
*
pWav
,
const
char
*
filename
,
const
drwav_data_format
*
pFormat
)
{
FILE
*
pFile
;
#if defined(_MSC_VER) && _MSC_VER >= 1400
if
(
fopen_s
(
&
pFile
,
filename
,
"wb"
)
!=
0
)
{
return
DRWAV_FALSE
;
}
#else
pFile
=
fopen
(
filename
,
"wb"
);
if
(
pFile
==
NULL
)
{
return
DRWAV_FALSE
;
}
#endif
return
drwav_init_write
(
pWav
,
pFormat
,
drwav__on_write_stdio
,
drwav__on_seek_stdio
,
(
void
*
)
pFile
);
}
drwav
*
drwav_open_file
(
const
char
*
filename
)
drwav
*
drwav_open_file
(
const
char
*
filename
)
{
{
FILE
*
pFile
;
FILE
*
pFile
;
...
@@ -917,6 +1067,29 @@ drwav* drwav_open_file(const char* filename)
...
@@ -917,6 +1067,29 @@ drwav* drwav_open_file(const char* filename)
return
pWav
;
return
pWav
;
}
}
drwav
*
drwav_open_file_write
(
const
char
*
filename
,
const
drwav_data_format
*
pFormat
)
{
FILE
*
pFile
;
#if defined(_MSC_VER) && _MSC_VER >= 1400
if
(
fopen_s
(
&
pFile
,
filename
,
"wb"
)
!=
0
)
{
return
NULL
;
}
#else
pFile
=
fopen
(
filename
,
"wb"
);
if
(
pFile
==
NULL
)
{
return
NULL
;
}
#endif
drwav
*
pWav
=
drwav_open_write
(
pFormat
,
drwav__on_write_stdio
,
drwav__on_seek_stdio
,
(
void
*
)
pFile
);
if
(
pWav
==
NULL
)
{
fclose
(
pFile
);
return
NULL
;
}
return
pWav
;
}
#endif //DR_WAV_NO_STDIO
#endif //DR_WAV_NO_STDIO
...
@@ -964,14 +1137,85 @@ static drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_see
...
@@ -964,14 +1137,85 @@ static drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_see
memory
->
currentReadPos
=
memory
->
dataSize
;
// Trying to seek too far forward.
memory
->
currentReadPos
=
memory
->
dataSize
;
// Trying to seek too far forward.
}
}
}
}
return
DRWAV_TRUE
;
}
static
size_t
drwav__on_write_memory
(
void
*
pUserData
,
const
void
*
pDataIn
,
size_t
bytesToWrite
)
{
drwav__memory_stream_write
*
memory
=
(
drwav__memory_stream_write
*
)
pUserData
;
drwav_assert
(
memory
!=
NULL
);
drwav_assert
(
memory
->
dataCapacity
>=
memory
->
currentWritePos
);
size_t
bytesRemaining
=
memory
->
dataCapacity
-
memory
->
currentWritePos
;
if
(
bytesRemaining
<
bytesToWrite
)
{
// Need to reallocate.
size_t
newDataCapacity
=
(
memory
->
dataCapacity
==
0
)
?
256
:
memory
->
dataCapacity
*
2
;
// If doubling wasn't enough, just make it the minimum required size to write the data.
if
((
newDataCapacity
-
memory
->
currentWritePos
)
<
bytesToWrite
)
{
newDataCapacity
=
memory
->
currentWritePos
+
bytesToWrite
;
}
void
*
pNewData
=
DRWAV_REALLOC
(
*
memory
->
ppData
,
newDataCapacity
);
if
(
pNewData
==
NULL
)
{
return
0
;
}
*
memory
->
ppData
=
pNewData
;
memory
->
dataCapacity
=
newDataCapacity
;
}
drwav_uint8
*
pDataOut
=
(
drwav_uint8
*
)(
*
memory
->
ppData
);
DRWAV_COPY_MEMORY
(
pDataOut
+
memory
->
currentWritePos
,
pDataIn
,
bytesToWrite
);
memory
->
currentWritePos
+=
bytesToWrite
;
if
(
memory
->
dataSize
<
memory
->
currentWritePos
)
{
memory
->
dataSize
=
memory
->
currentWritePos
;
}
*
memory
->
pDataSize
=
memory
->
dataSize
;
return
bytesToWrite
;
}
static
drwav_bool32
drwav__on_seek_memory_write
(
void
*
pUserData
,
int
offset
,
drwav_seek_origin
origin
)
{
drwav__memory_stream_write
*
memory
=
(
drwav__memory_stream_write
*
)
pUserData
;
drwav_assert
(
memory
!=
NULL
);
if
(
origin
==
drwav_seek_origin_current
)
{
if
(
offset
>
0
)
{
if
(
memory
->
currentWritePos
+
offset
>
memory
->
dataSize
)
{
offset
=
(
int
)(
memory
->
dataSize
-
memory
->
currentWritePos
);
// Trying to seek too far forward.
}
}
else
{
if
(
memory
->
currentWritePos
<
(
size_t
)
-
offset
)
{
offset
=
-
(
int
)
memory
->
currentWritePos
;
// Trying to seek too far backwards.
}
}
// This will never underflow thanks to the clamps above.
memory
->
currentWritePos
+=
offset
;
}
else
{
if
((
drwav_uint32
)
offset
<=
memory
->
dataSize
)
{
memory
->
currentWritePos
=
offset
;
}
else
{
memory
->
currentWritePos
=
memory
->
dataSize
;
// Trying to seek too far forward.
}
}
return
DRWAV_TRUE
;
return
DRWAV_TRUE
;
}
}
drwav_bool32
drwav_init_memory
(
drwav
*
pWav
,
const
void
*
data
,
size_t
dataSize
)
drwav_bool32
drwav_init_memory
(
drwav
*
pWav
,
const
void
*
data
,
size_t
dataSize
)
{
{
if
(
data
==
NULL
||
dataSize
==
0
)
{
return
DRWAV_FALSE
;
}
drwav__memory_stream
memoryStream
;
drwav__memory_stream
memoryStream
;
drwav_zero_memory
(
&
memoryStream
,
sizeof
(
memoryStream
));
memoryStream
.
data
=
(
const
unsigned
char
*
)
data
;
memoryStream
.
data
=
(
const
unsigned
char
*
)
data
;
memoryStream
.
dataSize
=
dataSize
;
memoryStream
.
dataSize
=
dataSize
;
memoryStream
.
currentReadPos
=
0
;
memoryStream
.
currentReadPos
=
0
;
...
@@ -985,9 +1229,40 @@ drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize)
...
@@ -985,9 +1229,40 @@ drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize)
return
DRWAV_TRUE
;
return
DRWAV_TRUE
;
}
}
drwav_bool32
drwav_init_memory_write
(
drwav
*
pWav
,
void
**
ppData
,
size_t
*
pDataSize
,
const
drwav_data_format
*
pFormat
)
{
if
(
ppData
==
NULL
)
{
return
DRWAV_FALSE
;
}
*
ppData
=
NULL
;
// Important because we're using realloc()!
*
pDataSize
=
0
;
drwav__memory_stream_write
memoryStreamWrite
;
drwav_zero_memory
(
&
memoryStreamWrite
,
sizeof
(
memoryStreamWrite
));
memoryStreamWrite
.
ppData
=
ppData
;
memoryStreamWrite
.
pDataSize
=
pDataSize
;
memoryStreamWrite
.
dataSize
=
0
;
memoryStreamWrite
.
dataCapacity
=
0
;
memoryStreamWrite
.
currentWritePos
=
0
;
if
(
!
drwav_init_write
(
pWav
,
pFormat
,
drwav__on_write_memory
,
drwav__on_seek_memory_write
,
(
void
*
)
&
memoryStreamWrite
))
{
return
DRWAV_FALSE
;
}
pWav
->
memoryStreamWrite
=
memoryStreamWrite
;
pWav
->
pUserData
=
&
pWav
->
memoryStreamWrite
;
return
DRWAV_TRUE
;
}
drwav
*
drwav_open_memory
(
const
void
*
data
,
size_t
dataSize
)
drwav
*
drwav_open_memory
(
const
void
*
data
,
size_t
dataSize
)
{
{
if
(
data
==
NULL
||
dataSize
==
0
)
{
return
NULL
;
}
drwav__memory_stream
memoryStream
;
drwav__memory_stream
memoryStream
;
drwav_zero_memory
(
&
memoryStream
,
sizeof
(
memoryStream
));
memoryStream
.
data
=
(
const
unsigned
char
*
)
data
;
memoryStream
.
data
=
(
const
unsigned
char
*
)
data
;
memoryStream
.
dataSize
=
dataSize
;
memoryStream
.
dataSize
=
dataSize
;
memoryStream
.
currentReadPos
=
0
;
memoryStream
.
currentReadPos
=
0
;
...
@@ -1002,6 +1277,33 @@ drwav* drwav_open_memory(const void* data, size_t dataSize)
...
@@ -1002,6 +1277,33 @@ drwav* drwav_open_memory(const void* data, size_t dataSize)
return
pWav
;
return
pWav
;
}
}
drwav
*
drwav_open_memory_write
(
void
**
ppData
,
size_t
*
pDataSize
,
const
drwav_data_format
*
pFormat
)
{
if
(
ppData
==
NULL
)
{
return
NULL
;
}
*
ppData
=
NULL
;
// Important because we're using realloc()!
*
pDataSize
=
0
;
drwav__memory_stream_write
memoryStreamWrite
;
drwav_zero_memory
(
&
memoryStreamWrite
,
sizeof
(
memoryStreamWrite
));
memoryStreamWrite
.
ppData
=
ppData
;
memoryStreamWrite
.
pDataSize
=
pDataSize
;
memoryStreamWrite
.
dataSize
=
0
;
memoryStreamWrite
.
dataCapacity
=
0
;
memoryStreamWrite
.
currentWritePos
=
0
;
drwav
*
pWav
=
drwav_open_write
(
pFormat
,
drwav__on_write_memory
,
drwav__on_seek_memory_write
,
(
void
*
)
&
memoryStreamWrite
);
if
(
pWav
==
NULL
)
{
return
NULL
;
}
pWav
->
memoryStreamWrite
=
memoryStreamWrite
;
pWav
->
pUserData
=
&
pWav
->
memoryStreamWrite
;
return
pWav
;
}
drwav_bool32
drwav_init
(
drwav
*
pWav
,
drwav_read_proc
onRead
,
drwav_seek_proc
onSeek
,
void
*
pUserData
)
drwav_bool32
drwav_init
(
drwav
*
pWav
,
drwav_read_proc
onRead
,
drwav_seek_proc
onSeek
,
void
*
pUserData
)
{
{
...
@@ -1070,7 +1372,7 @@ drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onS
...
@@ -1070,7 +1372,7 @@ drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onS
return
DRWAV_FALSE
;
return
DRWAV_FALSE
;
}
}
if
(
drwav__bytes_to_u64
(
chunkSize
)
<
8
4
)
{
if
(
drwav__bytes_to_u64
(
chunkSize
)
<
8
0
)
{
return
DRWAV_FALSE
;
return
DRWAV_FALSE
;
}
}
...
@@ -1212,16 +1514,174 @@ drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onS
...
@@ -1212,16 +1514,174 @@ drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onS
return
DRWAV_TRUE
;
return
DRWAV_TRUE
;
}
}
drwav_bool32
drwav_init_write
(
drwav
*
pWav
,
const
drwav_data_format
*
pFormat
,
drwav_write_proc
onWrite
,
drwav_seek_proc
onSeek
,
void
*
pUserData
)
{
if
(
onWrite
==
NULL
||
onSeek
==
NULL
)
{
return
DRWAV_FALSE
;
}
// Not currently supporting compressed formats. Will need to add support for the "fact" chunk before we enable this.
if
(
pFormat
->
format
==
DR_WAVE_FORMAT_EXTENSIBLE
)
{
return
DRWAV_FALSE
;
}
if
(
pFormat
->
format
==
DR_WAVE_FORMAT_ADPCM
||
pFormat
->
format
==
DR_WAVE_FORMAT_DVI_ADPCM
)
{
return
DRWAV_FALSE
;
}
drwav_zero_memory
(
pWav
,
sizeof
(
*
pWav
));
pWav
->
onWrite
=
onWrite
;
pWav
->
onSeek
=
onSeek
;
pWav
->
pUserData
=
pUserData
;
pWav
->
fmt
.
formatTag
=
(
drwav_uint16
)
pFormat
->
format
;
pWav
->
fmt
.
channels
=
(
drwav_uint16
)
pFormat
->
channels
;
pWav
->
fmt
.
sampleRate
=
pFormat
->
sampleRate
;
pWav
->
fmt
.
avgBytesPerSec
=
(
drwav_uint32
)((
pFormat
->
bitsPerSample
*
pFormat
->
sampleRate
*
pFormat
->
channels
)
>>
3
);
pWav
->
fmt
.
blockAlign
=
(
drwav_uint16
)((
pFormat
->
channels
*
pFormat
->
bitsPerSample
)
>>
3
);
pWav
->
fmt
.
bitsPerSample
=
(
drwav_uint16
)
pFormat
->
bitsPerSample
;
pWav
->
fmt
.
extendedSize
=
0
;
size_t
runningPos
=
0
;
// "RIFF" chunk.
drwav_uint64
chunkSizeRIFF
=
0
;
if
(
pFormat
->
container
==
drwav_container_riff
)
{
runningPos
+=
pWav
->
onWrite
(
pUserData
,
"RIFF"
,
4
);
runningPos
+=
pWav
->
onWrite
(
pUserData
,
&
chunkSizeRIFF
,
4
);
runningPos
+=
pWav
->
onWrite
(
pUserData
,
"WAVE"
,
4
);
}
else
{
runningPos
+=
pWav
->
onWrite
(
pUserData
,
drwavGUID_W64_RIFF
,
16
);
runningPos
+=
pWav
->
onWrite
(
pUserData
,
&
chunkSizeRIFF
,
8
);
runningPos
+=
pWav
->
onWrite
(
pUserData
,
drwavGUID_W64_WAVE
,
16
);
}
// "fmt " chunk.
drwav_uint64
chunkSizeFMT
;
if
(
pFormat
->
container
==
drwav_container_riff
)
{
chunkSizeFMT
=
16
;
runningPos
+=
pWav
->
onWrite
(
pUserData
,
"fmt "
,
4
);
runningPos
+=
pWav
->
onWrite
(
pUserData
,
&
chunkSizeFMT
,
4
);
}
else
{
chunkSizeFMT
=
40
;
runningPos
+=
pWav
->
onWrite
(
pUserData
,
drwavGUID_W64_FMT
,
16
);
runningPos
+=
pWav
->
onWrite
(
pUserData
,
&
chunkSizeFMT
,
8
);
}
runningPos
+=
pWav
->
onWrite
(
pUserData
,
&
pWav
->
fmt
.
formatTag
,
2
);
runningPos
+=
pWav
->
onWrite
(
pUserData
,
&
pWav
->
fmt
.
channels
,
2
);
runningPos
+=
pWav
->
onWrite
(
pUserData
,
&
pWav
->
fmt
.
sampleRate
,
4
);
runningPos
+=
pWav
->
onWrite
(
pUserData
,
&
pWav
->
fmt
.
avgBytesPerSec
,
4
);
runningPos
+=
pWav
->
onWrite
(
pUserData
,
&
pWav
->
fmt
.
blockAlign
,
2
);
runningPos
+=
pWav
->
onWrite
(
pUserData
,
&
pWav
->
fmt
.
bitsPerSample
,
2
);
pWav
->
dataChunkDataPos
=
runningPos
;
pWav
->
dataChunkDataSize
=
0
;
// "data" chunk.
drwav_uint64
chunkSizeDATA
=
0
;
if
(
pFormat
->
container
==
drwav_container_riff
)
{
runningPos
+=
pWav
->
onWrite
(
pUserData
,
"data"
,
4
);
runningPos
+=
pWav
->
onWrite
(
pUserData
,
&
chunkSizeDATA
,
4
);
}
else
{
runningPos
+=
pWav
->
onWrite
(
pUserData
,
drwavGUID_W64_DATA
,
16
);
runningPos
+=
pWav
->
onWrite
(
pUserData
,
&
chunkSizeDATA
,
8
);
}
// Simple validation.
if
(
pFormat
->
container
==
drwav_container_riff
)
{
if
(
runningPos
!=
20
+
chunkSizeFMT
+
8
)
{
return
DRWAV_FALSE
;
}
}
else
{
if
(
runningPos
!=
40
+
chunkSizeFMT
+
24
)
{
return
DRWAV_FALSE
;
}
}
// Set some properties for the client's convenience.
pWav
->
container
=
pFormat
->
container
;
pWav
->
channels
=
(
drwav_uint16
)
pFormat
->
channels
;
pWav
->
sampleRate
=
pFormat
->
sampleRate
;
pWav
->
bitsPerSample
=
(
drwav_uint16
)
pFormat
->
bitsPerSample
;
pWav
->
bytesPerSample
=
(
drwav_uint16
)(
pFormat
->
bitsPerSample
>>
3
);
pWav
->
translatedFormatTag
=
(
drwav_uint16
)
pFormat
->
format
;
return
DRWAV_TRUE
;
}
void
drwav_uninit
(
drwav
*
pWav
)
void
drwav_uninit
(
drwav
*
pWav
)
{
{
if
(
pWav
==
NULL
)
{
if
(
pWav
==
NULL
)
{
return
;
return
;
}
}
// If the drwav object was opened in write mode we'll need to finialize a few things:
// - Make sure the "data" chunk is aligned to 16-bits
// - Set the size of the "data" chunk.
if
(
pWav
->
onWrite
!=
NULL
)
{
// Padding. Do not adjust pWav->dataChunkDataSize - this should not include the padding.
drwav_uint32
paddingSize
=
0
;
if
(
pWav
->
container
==
drwav_container_riff
)
{
paddingSize
=
(
drwav_uint32
)(
pWav
->
dataChunkDataSize
%
2
);
}
else
{
paddingSize
=
(
drwav_uint32
)(
pWav
->
dataChunkDataSize
%
8
);
}
if
(
paddingSize
>
0
)
{
drwav_uint64
paddingData
=
0
;
pWav
->
onWrite
(
pWav
->
pUserData
,
&
paddingData
,
paddingSize
);
}
// Chunk sizes.
if
(
pWav
->
onSeek
)
{
if
(
pWav
->
container
==
drwav_container_riff
)
{
// The "RIFF" chunk size.
if
(
pWav
->
onSeek
(
pWav
->
pUserData
,
4
,
drwav_seek_origin_start
))
{
drwav_uint32
riffChunkSize
=
36
;
if
(
pWav
->
dataChunkDataSize
<=
(
0xFFFFFFFF
-
36
))
{
riffChunkSize
=
36
+
(
drwav_uint32
)
pWav
->
dataChunkDataSize
;
}
else
{
riffChunkSize
=
0xFFFFFFFF
;
}
pWav
->
onWrite
(
pWav
->
pUserData
,
&
riffChunkSize
,
4
);
}
// the "data" chunk size.
if
(
pWav
->
onSeek
(
pWav
->
pUserData
,
(
int
)
pWav
->
dataChunkDataPos
+
4
,
drwav_seek_origin_start
))
{
drwav_uint32
dataChunkSize
=
0
;
if
(
pWav
->
dataChunkDataSize
<=
0xFFFFFFFF
)
{
dataChunkSize
=
(
drwav_uint32
)
pWav
->
dataChunkDataSize
;
}
else
{
dataChunkSize
=
0xFFFFFFFF
;
}
pWav
->
onWrite
(
pWav
->
pUserData
,
&
dataChunkSize
,
4
);
}
}
else
{
// The "RIFF" chunk size.
if
(
pWav
->
onSeek
(
pWav
->
pUserData
,
16
,
drwav_seek_origin_start
))
{
drwav_uint64
riffChunkSize
=
80
+
24
+
pWav
->
dataChunkDataSize
;
pWav
->
onWrite
(
pWav
->
pUserData
,
&
riffChunkSize
,
8
);
}
// The "data" chunk size.
if
(
pWav
->
onSeek
(
pWav
->
pUserData
,
(
int
)
pWav
->
dataChunkDataPos
+
16
,
drwav_seek_origin_start
))
{
drwav_uint64
dataChunkSize
=
24
+
pWav
->
dataChunkDataSize
;
// +24 because W64 includes the size of the GUID and size fields.
pWav
->
onWrite
(
pWav
->
pUserData
,
&
dataChunkSize
,
8
);
}
}
}
}
#ifndef DR_WAV_NO_STDIO
#ifndef DR_WAV_NO_STDIO
// If we opened the file with drwav_open_file() we will want to close the file handle. We can know whether or not drwav_open_file()
// If we opened the file with drwav_open_file() we will want to close the file handle. We can know whether or not drwav_open_file()
// was used by looking at the onRead and onSeek callbacks.
// was used by looking at the onRead and onSeek callbacks.
if
(
pWav
->
onRead
==
drwav__on_read_stdio
)
{
if
(
pWav
->
onRead
==
drwav__on_read_stdio
||
pWav
->
onWrite
==
drwav__on_write_stdio
)
{
fclose
((
FILE
*
)
pWav
->
pUserData
);
fclose
((
FILE
*
)
pWav
->
pUserData
);
}
}
#endif
#endif
...
@@ -1243,6 +1703,21 @@ drwav* drwav_open(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserDat
...
@@ -1243,6 +1703,21 @@ drwav* drwav_open(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserDat
return
pWav
;
return
pWav
;
}
}
drwav
*
drwav_open_write
(
const
drwav_data_format
*
pFormat
,
drwav_write_proc
onWrite
,
drwav_seek_proc
onSeek
,
void
*
pUserData
)
{
drwav
*
pWav
=
(
drwav
*
)
DRWAV_MALLOC
(
sizeof
(
*
pWav
));
if
(
pWav
==
NULL
)
{
return
NULL
;
}
if
(
!
drwav_init_write
(
pWav
,
pFormat
,
onWrite
,
onSeek
,
pUserData
))
{
DRWAV_FREE
(
pWav
);
return
NULL
;
}
return
pWav
;
}
void
drwav_close
(
drwav
*
pWav
)
void
drwav_close
(
drwav
*
pWav
)
{
{
drwav_uninit
(
pWav
);
drwav_uninit
(
pWav
);
...
@@ -1403,6 +1878,34 @@ fallback:
...
@@ -1403,6 +1878,34 @@ fallback:
}
}
size_t
drwav_write_raw
(
drwav
*
pWav
,
size_t
bytesToWrite
,
const
void
*
pData
)
{
if
(
pWav
==
NULL
||
bytesToWrite
==
0
||
pData
==
NULL
)
{
return
0
;
}
size_t
bytesWritten
=
pWav
->
onWrite
(
pWav
->
pUserData
,
pData
,
bytesToWrite
);
pWav
->
dataChunkDataSize
+=
bytesWritten
;
return
bytesWritten
;
}
drwav_uint64
drwav_write
(
drwav
*
pWav
,
drwav_uint64
samplesToWrite
,
const
void
*
pData
)
{
if
(
pWav
==
NULL
||
samplesToWrite
==
0
||
pData
==
NULL
)
{
return
0
;
}
drwav_uint64
bytesToWrite
=
((
samplesToWrite
*
pWav
->
bitsPerSample
)
/
8
);
if
(
bytesToWrite
>
SIZE_MAX
)
{
return
0
;
}
size_t
bytesWritten
=
drwav_write_raw
(
pWav
,
(
size_t
)
bytesToWrite
,
pData
);
return
((
drwav_uint64
)
bytesWritten
*
8
)
/
pWav
->
bitsPerSample
;
}
#ifndef DR_WAV_NO_CONVERSION_API
#ifndef DR_WAV_NO_CONVERSION_API
static
unsigned
short
g_drwavAlawTable
[
256
]
=
{
static
unsigned
short
g_drwavAlawTable
[
256
]
=
{
0xEA80
,
0xEB80
,
0xE880
,
0xE980
,
0xEE80
,
0xEF80
,
0xEC80
,
0xED80
,
0xE280
,
0xE380
,
0xE080
,
0xE180
,
0xE680
,
0xE780
,
0xE480
,
0xE580
,
0xEA80
,
0xEB80
,
0xE880
,
0xE980
,
0xEE80
,
0xEF80
,
0xEC80
,
0xED80
,
0xE280
,
0xE380
,
0xE080
,
0xE180
,
0xE680
,
0xE780
,
0xE480
,
0xE580
,
...
@@ -2853,6 +3356,9 @@ void drwav_free(void* pDataReturnedByOpenAndRead)
...
@@ -2853,6 +3356,9 @@ void drwav_free(void* pDataReturnedByOpenAndRead)
// REVISION HISTORY
// REVISION HISTORY
//
//
// v0.7 - 2017-11-04
// - Add writing APIs.
//
// v0.6 - 2017-08-16
// v0.6 - 2017-08-16
// - API CHANGE: Rename dr_* types to drwav_*.
// - API CHANGE: Rename dr_* types to drwav_*.
// - Add support for custom implementations of malloc(), realloc(), etc.
// - Add support for custom implementations of malloc(), realloc(), etc.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment