Skip to content

Commit 573abb9

Browse files
committed
Merge branch 'release/1.1.3'
2 parents 3d899f5 + 0ac49bc commit 573abb9

File tree

4 files changed

+90
-29
lines changed

4 files changed

+90
-29
lines changed

AudioFile.h

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,11 @@ class AudioFile
109109
//=============================================================
110110
/** Loads an audio file from data in memory */
111111
bool loadFromMemory (const std::vector<uint8_t>& fileData);
112-
112+
113+
//=============================================================
114+
/** Saves an audio file to data in memory */
115+
bool saveToMemory (std::vector<uint8_t>& fileData, AudioFileFormat format = AudioFileFormat::Wave);
116+
113117
//=============================================================
114118
/** @Returns the sample rate */
115119
uint32_t getSampleRate() const;
@@ -190,10 +194,10 @@ class AudioFile
190194
//=============================================================
191195
bool decodeWaveFile (const std::vector<uint8_t>& fileData);
192196
bool decodeAiffFile (const std::vector<uint8_t>& fileData);
193-
197+
194198
//=============================================================
195-
bool saveToWaveFile (const std::string& filePath);
196-
bool saveToAiffFile (const std::string& filePath);
199+
bool encodeWaveFile (std::vector<uint8_t>& fileData);
200+
bool encodeAiffFile (std::vector<uint8_t>& fileData);
197201

198202
//=============================================================
199203
void clearAudioBuffer();
@@ -889,25 +893,31 @@ void AudioFile<T>::addSampleRateToAiffData (std::vector<uint8_t>& fileData, uint
889893
//=============================================================
890894
template <class T>
891895
bool AudioFile<T>::save (const std::string& filePath, AudioFileFormat format)
896+
{
897+
std::vector<uint8_t> fileData;
898+
return saveToMemory (fileData, format) && writeDataToFile (fileData, filePath);
899+
}
900+
901+
//=============================================================
902+
template <class T>
903+
bool AudioFile<T>::saveToMemory (std::vector<uint8_t>& fileData, AudioFileFormat format)
892904
{
893905
if (format == AudioFileFormat::Wave)
894906
{
895-
return saveToWaveFile (filePath);
907+
return encodeWaveFile (fileData);
896908
}
897909
else if (format == AudioFileFormat::Aiff)
898910
{
899-
return saveToAiffFile (filePath);
911+
return encodeAiffFile (fileData);
900912
}
901913

902914
return false;
903915
}
904916

905917
//=============================================================
906918
template <class T>
907-
bool AudioFile<T>::saveToWaveFile (const std::string& filePath)
908-
{
909-
std::vector<uint8_t> fileData;
910-
919+
bool AudioFile<T>::encodeWaveFile (std::vector<uint8_t>& fileData)
920+
{
911921
int32_t dataChunkSize = getNumSamplesPerChannel() * (getNumChannels() * bitDepth / 8);
912922
int16_t audioFormat = bitDepth == 32 && std::is_floating_point_v<T> ? WavAudioFormat::IEEEFloat : WavAudioFormat::PCM;
913923
int32_t formatChunkSize = audioFormat == WavAudioFormat::PCM ? 16 : 18;
@@ -985,9 +995,22 @@ bool AudioFile<T>::saveToWaveFile (const std::string& filePath)
985995
int32_t sampleAsInt;
986996

987997
if (audioFormat == WavAudioFormat::IEEEFloat)
988-
sampleAsInt = (int32_t) reinterpret_cast<int32_t&> (samples[channel][i]);
998+
{
999+
if constexpr (std::is_same_v<T, float>)
1000+
{
1001+
sampleAsInt = (int32_t) reinterpret_cast<int32_t&> (samples[channel][i]);
1002+
}
1003+
else if constexpr (std::is_same_v<T, double>)
1004+
{
1005+
auto sampleAsFloat = (float) samples[channel][i];
1006+
float& referenceToSample = sampleAsFloat;
1007+
sampleAsInt = (int32_t) reinterpret_cast<int32_t&> (referenceToSample);
1008+
}
1009+
}
9891010
else // assume PCM
1011+
{
9901012
sampleAsInt = AudioSampleConverter<T>::sampleToThirtyTwoBitInt (samples[channel][i]);
1013+
}
9911014

9921015
addInt32ToFileData (fileData, sampleAsInt, Endianness::LittleEndian);
9931016
}
@@ -1011,20 +1034,17 @@ bool AudioFile<T>::saveToWaveFile (const std::string& filePath)
10111034
// check that the various sizes we put in the metadata are correct
10121035
if (fileSizeInBytes != static_cast<int32_t> (fileData.size() - 8) || dataChunkSize != (getNumSamplesPerChannel() * getNumChannels() * (bitDepth / 8)))
10131036
{
1014-
reportError ("ERROR: couldn't save file to " + filePath);
1037+
reportError ("ERROR: Incorrect file or data chunk size.");
10151038
return false;
10161039
}
10171040

1018-
// try to write the file
1019-
return writeDataToFile (fileData, filePath);
1041+
return true;
10201042
}
10211043

10221044
//=============================================================
10231045
template <class T>
1024-
bool AudioFile<T>::saveToAiffFile (const std::string& filePath)
1025-
{
1026-
std::vector<uint8_t> fileData;
1027-
1046+
bool AudioFile<T>::encodeAiffFile (std::vector<uint8_t>& fileData)
1047+
{
10281048
int32_t numBytesPerSample = bitDepth / 8;
10291049
int32_t numBytesPerFrame = numBytesPerSample * getNumChannels();
10301050
int32_t totalNumAudioSampleBytes = getNumSamplesPerChannel() * numBytesPerFrame;
@@ -1116,12 +1136,11 @@ bool AudioFile<T>::saveToAiffFile (const std::string& filePath)
11161136
// check that the various sizes we put in the metadata are correct
11171137
if (fileSizeInBytes != static_cast<int32_t> (fileData.size() - 8) || soundDataChunkSize != getNumSamplesPerChannel() * numBytesPerFrame + 8)
11181138
{
1119-
reportError ("ERROR: couldn't save file to " + filePath);
1139+
reportError ("ERROR: Incorrect file or data chunk size.");
11201140
return false;
11211141
}
11221142

1123-
// try to write the file
1124-
return writeDataToFile (fileData, filePath);
1143+
return true;
11251144
}
11261145

11271146
//=============================================================

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#===============================================================================
22
cmake_minimum_required (VERSION 3.12)
33

4-
project ("AudioFile" VERSION 1.1.2
4+
project ("AudioFile" VERSION 1.1.3
55
DESCRIPTION "A simple C++ library for reading and writing audio files."
66
HOMEPAGE_URL "https://github.com/adamstark/AudioFile")
77

README.md

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<!-- Version and License Badges -->
44

5-
![Version](https://img.shields.io/badge/version-1.1.2-green.svg?style=flat-square)
5+
![Version](https://img.shields.io/badge/version-1.1.3-green.svg?style=flat-square)
66
![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)
77
![Language](https://img.shields.io/badge/language-C++-yellow.svg?style=flat-square)
88

@@ -53,7 +53,7 @@ AudioFile is written and maintained by Adam Stark.
5353

5454
for (int i = 0; i < numSamples; i++)
5555
{
56-
double currentSample = audioFile.samples[channel][i];
56+
double currentSample = audioFile.samples[channel][i];
5757
}
5858

5959
### Replace the AudioFile audio buffer with another
@@ -119,6 +119,17 @@ AudioFile is written and maintained by Adam Stark.
119119
// Aiff file
120120
audioFile.save ("path/to/desired/audioFile.aif", AudioFileFormat::Aiff);
121121

122+
### Save the audio file to memory
123+
124+
Write the audio file data directly to a vector of bytes (without writing to a file on disk):
125+
126+
std::vector<uint8_t> fileData;
127+
audioFile.saveToMemory (fileData, AudioFileFormat::Wave);
128+
129+
or
130+
131+
audioFile.saveToMemory (fileData, AudioFileFormat::Aiff);
132+
122133
## Examples
123134

124135
Please see the `examples` folder for some examples on library usage.
@@ -178,6 +189,11 @@ If you prefer not to see these messages, you can disable this error logging beha
178189

179190
## Versions
180191

192+
##### 1.1.3 - 31st May 2025
193+
194+
- Added saveToMemory() function to save audio data to bytes
195+
- Bug fixes and extra testing
196+
181197
##### 1.1.2 - 18th November 2024
182198

183199
- Improved AIFF sample rate calculations
@@ -249,13 +265,15 @@ Many thanks to the following people for their contributions to this library:
249265
- [cgraf78](https://github.com/cgraf78)
250266
- [emiro85](https://github.com/emiro85)
251267
- [encoded](https://github.com/encoded)
268+
- [gitelope](https://github.com/gitelope)
252269
- [heartofrain](https://github.com/heartofrain)
253270
- [helloimmatt](https://github.com/helloimmatt/)
254271
- [leocstone](https://github.com/leocstone)
255272
- [MatthieuHernandez](https://github.com/MatthieuHernandez)
256273
- [Metalsofa](https://github.com/Metalsofa)
257274
- [mrpossoms](https://github.com/mrpossoms)
258275
- [mynameisjohn](https://github.com/mynameisjohn)
276+
- [nicmell](https://github.com/nicmell)
259277
- [Sidelobe](https://github.com/Sidelobe)
260278
- [sschaetz](https://github.com/sschaetz)
261279
- [Yhcrown](https://github.com/Yhcrown)

tests/FileWritingTests.cpp

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,9 @@ void writeTestAudioFile (int numChannels, int sampleRate, int bitDepth, AudioFil
8585
REQUIRE (OK);
8686

8787
//-----------------------------------------------------------------
88-
// for some key bit depths and mono/stereo files, read in the audio file
89-
// we just wrote and do a sample-by-sample comparison to confirm we are
90-
// writing good files
91-
if ((bitDepth == 8 || bitDepth == 16 || bitDepth == 24) && numChannels <= 2)
88+
// read in the audio file we just wrote and do a sample-by-sample
89+
// comparison to confirm we are writing good files
90+
if (numChannels <= 2)
9291
{
9392
AudioFile<T> audioFileReader;
9493
audioFileReader.load (filePath);
@@ -136,13 +135,38 @@ TEST_SUITE ("Writing Tests")
136135
for (auto& format : audioFormats)
137136
{
138137
auto fmt_str = format == AudioFileFormat::Wave ? "wav" : "aiff";
139-
std::cerr << sampleRate << "Hz " << bitDepth << "-bit " << channels << " " << fmt_str << " (floating point)" << std::endl;
138+
std::cerr << sampleRate << "Hz " << bitDepth << "-bit " << channels << " " << fmt_str << " (float)" << std::endl;
140139
writeTestAudioFile<float> (channels, sampleRate, bitDepth, format);
141140
}
142141
}
143142
}
144143
}
145144
}
145+
146+
//=============================================================
147+
TEST_CASE ("WritingTest::WriteSineToneToManyFormats::DoublePrecision")
148+
{
149+
std::vector<int> sampleRates = {22050, 44100, 48000, 96000};
150+
std::vector<int> bitDepths = {8, 16, 24, 32};
151+
std::vector<int> numChannels = {1, 2, 8};
152+
std::vector<AudioFileFormat> audioFormats = {AudioFileFormat::Wave, AudioFileFormat::Aiff};
153+
154+
for (auto& sampleRate : sampleRates)
155+
{
156+
for (auto& bitDepth : bitDepths)
157+
{
158+
for (auto& channels : numChannels)
159+
{
160+
for (auto& format : audioFormats)
161+
{
162+
auto fmt_str = format == AudioFileFormat::Wave ? "wav" : "aiff";
163+
std::cerr << sampleRate << "Hz " << bitDepth << "-bit " << channels << " " << fmt_str << " (double)" << std::endl;
164+
writeTestAudioFile<double> (channels, sampleRate, bitDepth, format);
165+
}
166+
}
167+
}
168+
}
169+
}
146170

147171
//=============================================================
148172
TEST_CASE ("WritingTest::WriteSineToneToManyFormats::Integer")

0 commit comments

Comments
 (0)