31#ifndef _AS_AudioFile_h
32#define _AS_AudioFile_h
46#include <unordered_map>
53 __pragma(warning (push))
54 __pragma(warning (disable : 4244))
55 __pragma(warning (disable : 4457))
56 __pragma(warning (disable : 4458))
57 __pragma(warning (disable : 4389))
58 __pragma(warning (disable : 4996))
59#elif defined (__GNUC__)
60 _Pragma(
"GCC diagnostic push")
61 _Pragma("GCC diagnostic ignored \"-Wconversion\"")
62 _Pragma("GCC diagnostic ignored \"-Wsign-compare\"")
63 _Pragma("GCC diagnostic ignored \"-Wshadow\"")
86 typedef std::vector<std::vector<T> > AudioBuffer;
99 bool load (std::string filePath);
181 enum class Endianness
188 AudioFileFormat determineAudioFileFormat (std::vector<uint8_t>& fileData);
189 bool decodeWaveFile (std::vector<uint8_t>& fileData);
190 bool decodeAiffFile (std::vector<uint8_t>& fileData);
193 bool saveToWaveFile (std::string filePath);
194 bool saveToAiffFile (std::string filePath);
197 void clearAudioBuffer();
200 int32_t fourBytesToInt (std::vector<uint8_t>& source,
int startIndex, Endianness endianness = Endianness::LittleEndian);
201 int16_t twoBytesToInt (std::vector<uint8_t>& source,
int startIndex, Endianness endianness = Endianness::LittleEndian);
202 int getIndexOfString (std::vector<uint8_t>& source, std::string s);
203 int getIndexOfChunk (std::vector<uint8_t>& source,
const std::string& chunkHeaderID,
int startIndex, Endianness endianness = Endianness::LittleEndian);
206 uint32_t getAiffSampleRate (std::vector<uint8_t>& fileData,
int sampleRateStartIndex);
207 bool tenByteMatch (std::vector<uint8_t>& v1,
int startIndex1, std::vector<uint8_t>& v2,
int startIndex2);
208 void addSampleRateToAiffData (std::vector<uint8_t>& fileData, uint32_t sampleRate);
211 void addStringToFileData (std::vector<uint8_t>& fileData, std::string s);
212 void addInt32ToFileData (std::vector<uint8_t>& fileData, int32_t i, Endianness endianness = Endianness::LittleEndian);
213 void addInt16ToFileData (std::vector<uint8_t>& fileData, int16_t i, Endianness endianness = Endianness::LittleEndian);
216 bool writeDataToFile (std::vector<uint8_t>& fileData, std::string filePath);
219 void reportError (std::string errorMessage);
225 bool logErrorsToConsole {
true};
269 static T
clamp (T v1, T minValue, T maxValue);
274static std::unordered_map <uint32_t, std::vector<uint8_t>> aiffSampleRateTable = {
275 {8000, {64, 11, 250, 0, 0, 0, 0, 0, 0, 0}},
276 {11025, {64, 12, 172, 68, 0, 0, 0, 0, 0, 0}},
277 {16000, {64, 12, 250, 0, 0, 0, 0, 0, 0, 0}},
278 {22050, {64, 13, 172, 68, 0, 0, 0, 0, 0, 0}},
279 {32000, {64, 13, 250, 0, 0, 0, 0, 0, 0, 0}},
280 {37800, {64, 14, 147, 168, 0, 0, 0, 0, 0, 0}},
281 {44056, {64, 14, 172, 24, 0, 0, 0, 0, 0, 0}},
282 {44100, {64, 14, 172, 68, 0, 0, 0, 0, 0, 0}},
283 {47250, {64, 14, 184, 146, 0, 0, 0, 0, 0, 0}},
284 {48000, {64, 14, 187, 128, 0, 0, 0, 0, 0, 0}},
285 {50000, {64, 14, 195, 80, 0, 0, 0, 0, 0, 0}},
286 {50400, {64, 14, 196, 224, 0, 0, 0, 0, 0, 0}},
287 {88200, {64, 15, 172, 68, 0, 0, 0, 0, 0, 0}},
288 {96000, {64, 15, 187, 128, 0, 0, 0, 0, 0, 0}},
289 {176400, {64, 16, 172, 68, 0, 0, 0, 0, 0, 0}},
290 {192000, {64, 16, 187, 128, 0, 0, 0, 0, 0, 0}},
291 {352800, {64, 17, 172, 68, 0, 0, 0, 0, 0, 0}},
292 {2822400, {64, 20, 172, 68, 0, 0, 0, 0, 0, 0}},
293 {5644800, {64, 21, 172, 68, 0, 0, 0, 0, 0, 0}}
325 samples[0].resize (0);
326 audioFileFormat = AudioFileFormat::NotLoaded;
348 return (
int)samples.size();
355 return getNumChannels() == 1;
362 return getNumChannels() == 2;
376 if (samples.size() > 0)
377 return (
int) samples[0].size();
386 return (
double)getNumSamplesPerChannel() / (double)sampleRate;
393 std::cout <<
"|======================================|" << std::endl;
394 std::cout <<
"Num Channels: " << getNumChannels() << std::endl;
395 std::cout <<
"Num Samples Per Channel: " << getNumSamplesPerChannel() << std::endl;
396 std::cout <<
"Sample Rate: " << sampleRate << std::endl;
397 std::cout <<
"Bit Depth: " << bitDepth << std::endl;
398 std::cout <<
"Length in Seconds: " << getLengthInSeconds() << std::endl;
399 std::cout <<
"|======================================|" << std::endl;
406 int numChannels = (int)newBuffer.size();
408 if (numChannels <= 0)
410 assert (
false &&
"The buffer you are trying to use has no channels");
414 size_t numSamples = newBuffer[0].size();
417 samples.resize (newBuffer.size());
419 for (
int k = 0; k < getNumChannels(); k++)
421 assert (newBuffer[k].size() == numSamples);
423 samples[k].resize (numSamples);
425 for (
size_t i = 0; i < numSamples; i++)
427 samples[k][i] = newBuffer[k][i];
438 samples.resize (numChannels);
439 setNumSamplesPerChannel (numSamples);
446 int originalSize = getNumSamplesPerChannel();
448 for (
int i = 0; i < getNumChannels();i++)
450 samples[i].resize (numSamples);
453 if (numSamples > originalSize)
454 std::fill (samples[i].begin() + originalSize, samples[i].end(), (T)0.);
462 int originalNumChannels = getNumChannels();
463 int originalNumSamplesPerChannel = getNumSamplesPerChannel();
465 samples.resize (numChannels);
469 if (numChannels > originalNumChannels)
471 for (
int i = originalNumChannels; i < numChannels; i++)
473 samples[i].resize (originalNumSamplesPerChannel);
474 std::fill (samples[i].begin(), samples[i].end(), (T)0.);
483 bitDepth = numBitsPerSample;
490 sampleRate = newSampleRate;
497 logErrorsToConsole = logErrors;
504 std::ifstream file (filePath, std::ios::binary);
509 reportError (
"ERROR: File doesn't exist or otherwise can't load file\n" + filePath);
513 std::vector<uint8_t> fileData;
515 file.unsetf (std::ios::skipws);
517 file.seekg (0, std::ios::end);
518 size_t length = file.tellg();
519 file.seekg (0, std::ios::beg);
522 fileData.resize (length);
524 file.read(
reinterpret_cast<char*
> (fileData.data()), length);
527 if (file.gcount() != length)
529 reportError (
"ERROR: Couldn't read entire file\n" + filePath);
535 if (fileData.size() < 12)
537 reportError (
"ERROR: File is not a valid audio file\n" + filePath);
542 return loadFromMemory (fileData);
551 audioFileFormat = determineAudioFileFormat (fileData);
553 if (audioFileFormat == AudioFileFormat::Wave)
555 return decodeWaveFile (fileData);
557 else if (audioFileFormat == AudioFileFormat::Aiff)
559 return decodeAiffFile (fileData);
563 reportError (
"Audio File Type: Error");
574 std::string headerChunkID (fileData.begin(), fileData.begin() + 4);
576 std::string format (fileData.begin() + 8, fileData.begin() + 12);
580 int indexOfDataChunk = getIndexOfChunk (fileData,
"data", 12);
581 int indexOfFormatChunk = getIndexOfChunk (fileData,
"fmt ", 12);
582 int indexOfXMLChunk = getIndexOfChunk (fileData,
"iXML", 12);
586 if (indexOfDataChunk == -1 || indexOfFormatChunk == -1 || headerChunkID !=
"RIFF" || format !=
"WAVE")
588 reportError (
"ERROR: this doesn't seem to be a valid .WAV file");
594 int f = indexOfFormatChunk;
595 std::string formatChunkID (fileData.begin() + f, fileData.begin() + f + 4);
597 uint16_t audioFormat = twoBytesToInt (fileData, f + 8);
598 uint16_t numChannels = twoBytesToInt (fileData, f + 10);
599 sampleRate = (uint32_t) fourBytesToInt (fileData, f + 12);
600 uint32_t numBytesPerSecond = fourBytesToInt (fileData, f + 16);
601 uint16_t numBytesPerBlock = twoBytesToInt (fileData, f + 20);
602 bitDepth = (int) twoBytesToInt (fileData, f + 22);
604 if (bitDepth >
sizeof (T) * 8)
606 std::string message =
"ERROR: you are trying to read a ";
607 message += std::to_string (bitDepth);
608 message +=
"-bit file using a ";
609 message += std::to_string (
sizeof (T) * 8);
610 message +=
"-bit sample type";
611 reportError (message);
615 uint16_t numBytesPerSample =
static_cast<uint16_t
> (bitDepth) / 8;
618 if (audioFormat != WavAudioFormat::PCM && audioFormat != WavAudioFormat::IEEEFloat && audioFormat != WavAudioFormat::Extensible)
620 reportError (
"ERROR: this .WAV file is encoded in a format that this library does not support at present");
625 if (numChannels < 1 || numChannels > 128)
627 reportError (
"ERROR: this WAV file seems to be an invalid number of channels (or corrupted?)");
632 if (numBytesPerSecond !=
static_cast<uint32_t
> ((numChannels * sampleRate * bitDepth) / 8) || numBytesPerBlock != (numChannels * numBytesPerSample))
634 reportError (
"ERROR: the header data in this WAV file seems to be inconsistent");
639 if (bitDepth != 8 && bitDepth != 16 && bitDepth != 24 && bitDepth != 32)
641 reportError (
"ERROR: this file has a bit depth that is not 8, 16, 24 or 32 bits");
647 int d = indexOfDataChunk;
648 std::string dataChunkID (fileData.begin() + d, fileData.begin() + d + 4);
649 int32_t dataChunkSize = fourBytesToInt (fileData, d + 4);
651 int numSamples = dataChunkSize / (numChannels * bitDepth / 8);
652 int samplesStartIndex = indexOfDataChunk + 8;
655 samples.resize (numChannels);
657 for (
int i = 0; i < numSamples; i++)
659 for (
int channel = 0; channel < numChannels; channel++)
661 int sampleIndex = samplesStartIndex + (numBytesPerBlock * i) + channel * numBytesPerSample;
663 if ((sampleIndex + (bitDepth / 8) - 1) >= fileData.size())
665 reportError (
"ERROR: read file error as the metadata indicates more samples than there are in the file data");
672 samples[channel].push_back (sample);
674 else if (bitDepth == 16)
676 int16_t sampleAsInt = twoBytesToInt (fileData, sampleIndex);
678 samples[channel].push_back (sample);
680 else if (bitDepth == 24)
682 int32_t sampleAsInt = 0;
683 sampleAsInt = (fileData[sampleIndex + 2] << 16) | (fileData[sampleIndex + 1] << 8) | fileData[sampleIndex];
685 if (sampleAsInt & 0x800000)
686 sampleAsInt = sampleAsInt | ~0xFFFFFF;
689 samples[channel].push_back (sample);
691 else if (bitDepth == 32)
693 int32_t sampleAsInt = fourBytesToInt (fileData, sampleIndex);
696 if (audioFormat == WavAudioFormat::IEEEFloat && std::is_floating_point_v<T>)
699 memcpy (&f, &sampleAsInt,
sizeof(int32_t));
707 samples[channel].push_back (sample);
718 if (indexOfXMLChunk != -1)
720 int32_t chunkSize = fourBytesToInt (fileData, indexOfXMLChunk + 4);
721 iXMLChunk = std::string ((
const char*) &fileData[indexOfXMLChunk + 8], chunkSize);
733 std::string headerChunkID (fileData.begin(), fileData.begin() + 4);
735 std::string format (fileData.begin() + 8, fileData.begin() + 12);
737 int audioFormat = format ==
"AIFF" ? AIFFAudioFormat::Uncompressed : format ==
"AIFC" ? AIFFAudioFormat::Compressed : AIFFAudioFormat::Error;
741 int indexOfCommChunk = getIndexOfChunk (fileData,
"COMM", 12, Endianness::BigEndian);
742 int indexOfSoundDataChunk = getIndexOfChunk (fileData,
"SSND", 12, Endianness::BigEndian);
743 int indexOfXMLChunk = getIndexOfChunk (fileData,
"iXML", 12, Endianness::BigEndian);
747 if (indexOfSoundDataChunk == -1 || indexOfCommChunk == -1 || headerChunkID !=
"FORM" || audioFormat == AIFFAudioFormat::Error)
749 reportError (
"ERROR: this doesn't seem to be a valid AIFF file");
755 int p = indexOfCommChunk;
756 std::string commChunkID (fileData.begin() + p, fileData.begin() + p + 4);
758 int16_t numChannels = twoBytesToInt (fileData, p + 8, Endianness::BigEndian);
759 int32_t numSamplesPerChannel = fourBytesToInt (fileData, p + 10, Endianness::BigEndian);
760 bitDepth = (int) twoBytesToInt (fileData, p + 14, Endianness::BigEndian);
761 sampleRate = getAiffSampleRate (fileData, p + 16);
763 if (bitDepth >
sizeof (T) * 8)
765 std::string message =
"ERROR: you are trying to read a ";
766 message += std::to_string (bitDepth);
767 message +=
"-bit file using a ";
768 message += std::to_string (
sizeof (T) * 8);
769 message +=
"-bit sample type";
770 reportError (message);
777 reportError (
"ERROR: this AIFF file has an unsupported sample rate");
782 if (numChannels < 1 ||numChannels > 2)
784 reportError (
"ERROR: this AIFF file seems to be neither mono nor stereo (perhaps multi-track, or corrupted?)");
789 if (bitDepth != 8 && bitDepth != 16 && bitDepth != 24 && bitDepth != 32)
791 reportError (
"ERROR: this file has a bit depth that is not 8, 16, 24 or 32 bits");
797 int s = indexOfSoundDataChunk;
798 std::string soundDataChunkID (fileData.begin() + s, fileData.begin() + s + 4);
799 int32_t soundDataChunkSize = fourBytesToInt (fileData, s + 4, Endianness::BigEndian);
800 int32_t offset = fourBytesToInt (fileData, s + 8, Endianness::BigEndian);
803 int numBytesPerSample = bitDepth / 8;
804 int numBytesPerFrame = numBytesPerSample * numChannels;
805 int totalNumAudioSampleBytes = numSamplesPerChannel * numBytesPerFrame;
806 int samplesStartIndex = s + 16 + (int)offset;
809 if ((soundDataChunkSize - 8) != totalNumAudioSampleBytes || totalNumAudioSampleBytes >
static_cast<long>(fileData.size() - samplesStartIndex))
811 reportError (
"ERROR: the metadatafor this file doesn't seem right");
816 samples.resize (numChannels);
818 for (
int i = 0; i < numSamplesPerChannel; i++)
820 for (
int channel = 0; channel < numChannels; channel++)
822 int sampleIndex = samplesStartIndex + (numBytesPerFrame * i) + channel * numBytesPerSample;
824 if ((sampleIndex + (bitDepth / 8) - 1) >= fileData.size())
826 reportError (
"ERROR: read file error as the metadata indicates more samples than there are in the file data");
833 samples[channel].push_back (sample);
835 else if (bitDepth == 16)
837 int16_t sampleAsInt = twoBytesToInt (fileData, sampleIndex, Endianness::BigEndian);
839 samples[channel].push_back (sample);
841 else if (bitDepth == 24)
843 int32_t sampleAsInt = 0;
844 sampleAsInt = (fileData[sampleIndex] << 16) | (fileData[sampleIndex + 1] << 8) | fileData[sampleIndex + 2];
846 if (sampleAsInt & 0x800000)
847 sampleAsInt = sampleAsInt | ~0xFFFFFF;
850 samples[channel].push_back (sample);
852 else if (bitDepth == 32)
854 int32_t sampleAsInt = fourBytesToInt (fileData, sampleIndex, Endianness::BigEndian);
857 if (audioFormat == AIFFAudioFormat::Compressed)
858 sample = (T)
reinterpret_cast<float&
> (sampleAsInt);
862 samples[channel].push_back (sample);
873 if (indexOfXMLChunk != -1)
875 int32_t chunkSize = fourBytesToInt (fileData, indexOfXMLChunk + 4);
876 iXMLChunk = std::string ((
const char*) &fileData[indexOfXMLChunk + 8], chunkSize);
886 for (
auto it : aiffSampleRateTable)
888 if (tenByteMatch (fileData, sampleRateStartIndex, it.second, 0))
899 for (
int i = 0; i < 10; i++)
901 if (v1[startIndex1 + i] != v2[startIndex2 + i])
912 if (aiffSampleRateTable.count (sampleRate) > 0)
914 for (
int i = 0; i < 10; i++)
915 fileData.push_back (aiffSampleRateTable[sampleRate][i]);
923 if (format == AudioFileFormat::Wave)
925 return saveToWaveFile (filePath);
927 else if (format == AudioFileFormat::Aiff)
929 return saveToAiffFile (filePath);
939 std::vector<uint8_t> fileData;
941 int32_t dataChunkSize = getNumSamplesPerChannel() * (getNumChannels() * bitDepth / 8);
942 int16_t audioFormat = bitDepth == 32 && std::is_floating_point_v<T> ? WavAudioFormat::IEEEFloat : WavAudioFormat::PCM;
943 int32_t formatChunkSize = audioFormat == WavAudioFormat::PCM ? 16 : 18;
944 int32_t iXMLChunkSize =
static_cast<int32_t
> (iXMLChunk.size());
948 addStringToFileData (fileData,
"RIFF");
952 int32_t fileSizeInBytes = 4 + formatChunkSize + 8 + 8 + dataChunkSize;
953 if (iXMLChunkSize > 0)
955 fileSizeInBytes += (8 + iXMLChunkSize);
958 addInt32ToFileData (fileData, fileSizeInBytes);
960 addStringToFileData (fileData,
"WAVE");
964 addStringToFileData (fileData,
"fmt ");
965 addInt32ToFileData (fileData, formatChunkSize);
966 addInt16ToFileData (fileData, audioFormat);
967 addInt16ToFileData (fileData, (int16_t)getNumChannels());
968 addInt32ToFileData (fileData, (int32_t)sampleRate);
970 int32_t numBytesPerSecond = (int32_t) ((getNumChannels() * sampleRate * bitDepth) / 8);
971 addInt32ToFileData (fileData, numBytesPerSecond);
973 int16_t numBytesPerBlock = getNumChannels() * (bitDepth / 8);
974 addInt16ToFileData (fileData, numBytesPerBlock);
976 addInt16ToFileData (fileData, (int16_t)bitDepth);
978 if (audioFormat == WavAudioFormat::IEEEFloat)
979 addInt16ToFileData (fileData, 0);
983 addStringToFileData (fileData,
"data");
984 addInt32ToFileData (fileData, dataChunkSize);
986 for (
int i = 0; i < getNumSamplesPerChannel(); i++)
988 for (
int channel = 0; channel < getNumChannels(); channel++)
993 fileData.push_back (
byte);
995 else if (bitDepth == 16)
998 addInt16ToFileData (fileData, sampleAsInt);
1000 else if (bitDepth == 24)
1005 bytes[2] = (uint8_t) (sampleAsIntAgain >> 16) & 0xFF;
1006 bytes[1] = (uint8_t) (sampleAsIntAgain >> 8) & 0xFF;
1007 bytes[0] = (uint8_t) sampleAsIntAgain & 0xFF;
1009 fileData.push_back (bytes[0]);
1010 fileData.push_back (bytes[1]);
1011 fileData.push_back (bytes[2]);
1013 else if (bitDepth == 32)
1015 int32_t sampleAsInt;
1017 if (audioFormat == WavAudioFormat::IEEEFloat)
1018 sampleAsInt = (int32_t)
reinterpret_cast<int32_t&
> (samples[channel][i]);
1022 addInt32ToFileData (fileData, sampleAsInt, Endianness::LittleEndian);
1026 assert (
false &&
"Trying to write a file with unsupported bit depth");
1034 if (iXMLChunkSize > 0)
1036 addStringToFileData (fileData,
"iXML");
1037 addInt32ToFileData (fileData, iXMLChunkSize);
1038 addStringToFileData (fileData, iXMLChunk);
1042 if (fileSizeInBytes !=
static_cast<int32_t
> (fileData.size() - 8) || dataChunkSize != (getNumSamplesPerChannel() * getNumChannels() * (bitDepth / 8)))
1044 reportError (
"ERROR: couldn't save file to " + filePath);
1049 return writeDataToFile (fileData, filePath);
1056 std::vector<uint8_t> fileData;
1058 int32_t numBytesPerSample = bitDepth / 8;
1059 int32_t numBytesPerFrame = numBytesPerSample * getNumChannels();
1060 int32_t totalNumAudioSampleBytes = getNumSamplesPerChannel() * numBytesPerFrame;
1061 int32_t soundDataChunkSize = totalNumAudioSampleBytes + 8;
1062 int32_t iXMLChunkSize =
static_cast<int32_t
> (iXMLChunk.size());
1066 addStringToFileData (fileData,
"FORM");
1070 int32_t fileSizeInBytes = 4 + 26 + 16 + totalNumAudioSampleBytes;
1071 if (iXMLChunkSize > 0)
1073 fileSizeInBytes += (8 + iXMLChunkSize);
1076 addInt32ToFileData (fileData, fileSizeInBytes, Endianness::BigEndian);
1078 addStringToFileData (fileData,
"AIFF");
1082 addStringToFileData (fileData,
"COMM");
1083 addInt32ToFileData (fileData, 18, Endianness::BigEndian);
1084 addInt16ToFileData (fileData, getNumChannels(), Endianness::BigEndian);
1085 addInt32ToFileData (fileData, getNumSamplesPerChannel(), Endianness::BigEndian);
1086 addInt16ToFileData (fileData, bitDepth, Endianness::BigEndian);
1087 addSampleRateToAiffData (fileData, sampleRate);
1091 addStringToFileData (fileData,
"SSND");
1092 addInt32ToFileData (fileData, soundDataChunkSize, Endianness::BigEndian);
1093 addInt32ToFileData (fileData, 0, Endianness::BigEndian);
1094 addInt32ToFileData (fileData, 0, Endianness::BigEndian);
1096 for (
int i = 0; i < getNumSamplesPerChannel(); i++)
1098 for (
int channel = 0; channel < getNumChannels(); channel++)
1103 fileData.push_back (
byte);
1105 else if (bitDepth == 16)
1108 addInt16ToFileData (fileData, sampleAsInt, Endianness::BigEndian);
1110 else if (bitDepth == 24)
1115 bytes[0] = (uint8_t) (sampleAsIntAgain >> 16) & 0xFF;
1116 bytes[1] = (uint8_t) (sampleAsIntAgain >> 8) & 0xFF;
1117 bytes[2] = (uint8_t) sampleAsIntAgain & 0xFF;
1119 fileData.push_back (bytes[0]);
1120 fileData.push_back (bytes[1]);
1121 fileData.push_back (bytes[2]);
1123 else if (bitDepth == 32)
1127 addInt32ToFileData (fileData, sampleAsInt, Endianness::BigEndian);
1131 assert (
false &&
"Trying to write a file with unsupported bit depth");
1139 if (iXMLChunkSize > 0)
1141 addStringToFileData (fileData,
"iXML");
1142 addInt32ToFileData (fileData, iXMLChunkSize, Endianness::BigEndian);
1143 addStringToFileData (fileData, iXMLChunk);
1147 if (fileSizeInBytes !=
static_cast<int32_t
> (fileData.size() - 8) || soundDataChunkSize != getNumSamplesPerChannel() * numBytesPerFrame + 8)
1149 reportError (
"ERROR: couldn't save file to " + filePath);
1154 return writeDataToFile (fileData, filePath);
1161 std::ofstream outputFile (filePath, std::ios::binary);
1163 if (outputFile.is_open())
1165 for (
size_t i = 0; i < fileData.size(); i++)
1167 char value = (char) fileData[i];
1168 outputFile.write (&value,
sizeof (
char));
1183 for (
size_t i = 0; i < s.length();i++)
1184 fileData.push_back ((uint8_t) s[i]);
1193 if (endianness == Endianness::LittleEndian)
1195 bytes[3] = (i >> 24) & 0xFF;
1196 bytes[2] = (i >> 16) & 0xFF;
1197 bytes[1] = (i >> 8) & 0xFF;
1198 bytes[0] = i & 0xFF;
1202 bytes[0] = (i >> 24) & 0xFF;
1203 bytes[1] = (i >> 16) & 0xFF;
1204 bytes[2] = (i >> 8) & 0xFF;
1205 bytes[3] = i & 0xFF;
1208 for (
int i = 0; i < 4; i++)
1209 fileData.push_back (bytes[i]);
1218 if (endianness == Endianness::LittleEndian)
1220 bytes[1] = (i >> 8) & 0xFF;
1221 bytes[0] = i & 0xFF;
1225 bytes[0] = (i >> 8) & 0xFF;
1226 bytes[1] = i & 0xFF;
1229 fileData.push_back (bytes[0]);
1230 fileData.push_back (bytes[1]);
1237 for (
size_t i = 0; i < samples.size();i++)
1249 std::string header (fileData.begin(), fileData.begin() + 4);
1251 if (header ==
"RIFF")
1252 return AudioFileFormat::Wave;
1253 else if (header ==
"FORM")
1254 return AudioFileFormat::Aiff;
1256 return AudioFileFormat::Error;
1263 if (source.size() >= (startIndex + 4))
1267 if (endianness == Endianness::LittleEndian)
1268 result = (source[startIndex + 3] << 24) | (source[startIndex + 2] << 16) | (source[startIndex + 1] << 8) | source[startIndex];
1270 result = (source[startIndex] << 24) | (source[startIndex + 1] << 16) | (source[startIndex + 2] << 8) | source[startIndex + 3];
1276 assert (
false &&
"Attempted to read four bytes from vector at position where out of bounds access would occur");
1287 if (endianness == Endianness::LittleEndian)
1288 result = (source[startIndex + 1] << 8) | source[startIndex];
1290 result = (source[startIndex] << 8) | source[startIndex + 1];
1300 int stringLength = (int)stringToSearchFor.length();
1302 for (
size_t i = 0; i < source.size() - stringLength;i++)
1304 std::string section (source.begin() + i, source.begin() + i + stringLength);
1306 if (section == stringToSearchFor)
1308 index =
static_cast<int> (i);
1320 constexpr int dataLen = 4;
1322 if (chunkHeaderID.size() != dataLen)
1324 assert (
false &&
"Invalid chunk header ID string");
1329 while (i < source.size() - dataLen)
1331 if (memcmp (&source[i], chunkHeaderID.data(), dataLen) == 0)
1339 if ((i + 4) >= source.size())
1342 auto chunkSize = fourBytesToInt (source, i, endianness);
1343 i += (dataLen + chunkSize);
1353 if (logErrorsToConsole)
1354 std::cout << errorMessage << std::endl;
1358template <
typename SignedType>
1359typename std::make_unsigned<SignedType>::type convertSignedToUnsigned (SignedType signedValue)
1361 static_assert (std::is_signed<SignedType>::value,
"The input value must be signed");
1363 typename std::make_unsigned<SignedType>::type unsignedValue =
static_cast<typename std::make_unsigned<SignedType>::type
> (1) + std::numeric_limits<SignedType>::max();
1365 unsignedValue += signedValue;
1366 return unsignedValue;
1372 SignedInt16_Min = -32768,
1373 SignedInt16_Max = 32767,
1374 UnsignedInt16_Min = 0,
1375 UnsignedInt16_Max = 65535,
1376 SignedInt24_Min = -8388608,
1377 SignedInt24_Max = 8388607,
1378 UnsignedInt24_Min = 0,
1379 UnsignedInt24_Max = 16777215
1386 if constexpr (std::is_floating_point<T>::value)
1388 return static_cast<T
> (sample) /
static_cast<T
> (std::numeric_limits<int32_t>::max());
1390 else if (std::numeric_limits<T>::is_integer)
1392 if constexpr (std::is_signed_v<T>)
1393 return static_cast<T
> (sample);
1395 return static_cast<T
> (clamp (
static_cast<T
> (sample + 2147483648), 0, 4294967295));
1403 if constexpr (std::is_floating_point<T>::value)
1408 if constexpr (std::is_same_v<T, float>)
1411 return std::numeric_limits<int32_t>::max();
1412 else if (sample <= -1.f)
1413 return std::numeric_limits<int32_t>::lowest() + 1;
1415 return static_cast<int32_t
> (sample * std::numeric_limits<int32_t>::max());
1419 return static_cast<int32_t
> (clamp (sample, -1., 1.) * std::numeric_limits<int32_t>::max());
1424 if constexpr (std::is_signed_v<T>)
1425 return static_cast<int32_t
> (clamp (sample, -2147483648LL, 2147483647LL));
1427 return static_cast<int32_t
> (clamp (sample, 0, 4294967295) - 2147483648);
1435 if constexpr (std::is_floating_point<T>::value)
1437 return static_cast<T
> (sample) /
static_cast<T
> (8388607.);
1439 else if (std::numeric_limits<T>::is_integer)
1441 if constexpr (std::is_signed_v<T>)
1442 return static_cast<T
> (clamp (sample, SignedInt24_Min, SignedInt24_Max));
1444 return static_cast<T
> (clamp (sample + 8388608, UnsignedInt24_Min, UnsignedInt24_Max));
1452 if constexpr (std::is_floating_point<T>::value)
1454 sample = clamp (sample, -1., 1.);
1455 return static_cast<int32_t
> (sample * 8388607.);
1459 if constexpr (std::is_signed_v<T>)
1460 return static_cast<int32_t
> (clamp (sample, SignedInt24_Min, SignedInt24_Max));
1462 return static_cast<int32_t
> (clamp (sample, UnsignedInt24_Min, UnsignedInt24_Max) + SignedInt24_Min);
1470 if constexpr (std::is_floating_point<T>::value)
1472 return static_cast<T
> (sample) /
static_cast<T
> (32767.);
1474 else if constexpr (std::numeric_limits<T>::is_integer)
1476 if constexpr (std::is_signed_v<T>)
1477 return static_cast<T
> (sample);
1479 return static_cast<T
> (convertSignedToUnsigned<int16_t> (sample));
1487 if constexpr (std::is_floating_point<T>::value)
1489 sample = clamp (sample, -1., 1.);
1490 return static_cast<int16_t
> (sample * 32767.);
1494 if constexpr (std::is_signed_v<T>)
1495 return static_cast<int16_t
> (clamp (sample, SignedInt16_Min, SignedInt16_Max));
1497 return static_cast<int16_t
> (clamp (sample, UnsignedInt16_Min, UnsignedInt16_Max) + SignedInt16_Min);
1505 if constexpr (std::is_floating_point<T>::value)
1507 sample = clamp (sample, -1., 1.);
1508 sample = (sample + 1.) / 2.;
1509 return static_cast<uint8_t
> (1 + (sample * 254));
1513 if constexpr (std::is_signed_v<T>)
1514 return static_cast<uint8_t
> (clamp (sample, -128, 127) + 128);
1516 return static_cast<uint8_t
> (clamp (sample, 0, 255));
1524 if constexpr (std::is_floating_point<T>::value)
1526 sample = clamp (sample, -1., 1.);
1527 return static_cast<int8_t
> (sample * (T)0x7F);
1531 if constexpr (std::is_signed_v<T>)
1532 return static_cast<int8_t
> (clamp (sample, -128, 127));
1534 return static_cast<int8_t
> (clamp (sample, 0, 255) - 128);
1542 if constexpr (std::is_floating_point<T>::value)
1544 return static_cast<T
> (sample - 128) /
static_cast<T
> (127.);
1546 else if (std::numeric_limits<T>::is_integer)
1548 if constexpr (std::is_unsigned_v<T>)
1549 return static_cast<T
> (sample);
1551 return static_cast<T
> (sample - 128);
1559 if constexpr (std::is_floating_point<T>::value)
1561 return static_cast<T
> (sample) /
static_cast<T
> (127.);
1563 else if constexpr (std::numeric_limits<T>::is_integer)
1565 if constexpr (std::is_signed_v<T>)
1566 return static_cast<T
> (sample);
1568 return static_cast<T
> (convertSignedToUnsigned<int8_t> (sample));
1576 value = std::min (value, maxValue);
1577 value = std::max (value, minValue);
1581#if defined (_MSC_VER)
1582 __pragma(warning (pop))
1583#elif defined (__GNUC__)
1584 _Pragma(
"GCC diagnostic pop")
AudioFileFormat
Definition: AudioFile.h:72
Definition: AudioFile.h:82
bool load(std::string filePath)
Definition: AudioFile.h:502
bool isMono() const
Definition: AudioFile.h:353
bool loadFromMemory(std::vector< uint8_t > &fileData)
Definition: AudioFile.h:548
void shouldLogErrorsToConsole(bool logErrors)
Definition: AudioFile.h:495
void setBitDepth(int numBitsPerSample)
Definition: AudioFile.h:481
void setSampleRate(uint32_t newSampleRate)
Definition: AudioFile.h:488
void setNumChannels(int numChannels)
Definition: AudioFile.h:460
bool isStereo() const
Definition: AudioFile.h:360
bool save(std::string filePath, AudioFileFormat format=AudioFileFormat::Wave)
Definition: AudioFile.h:921
void setNumSamplesPerChannel(int numSamples)
Definition: AudioFile.h:444
int getNumChannels() const
Definition: AudioFile.h:346
int getBitDepth() const
Definition: AudioFile.h:367
double getLengthInSeconds() const
Definition: AudioFile.h:384
void printSummary() const
Definition: AudioFile.h:391
uint32_t getSampleRate() const
Definition: AudioFile.h:339
std::string iXMLChunk
Definition: AudioFile.h:176
AudioFile(std::string filePath)
Definition: AudioFile.h:331
void setAudioBufferSize(int numChannels, int numSamples)
Definition: AudioFile.h:436
int getNumSamplesPerChannel() const
Definition: AudioFile.h:374
AudioFile()
Definition: AudioFile.h:320
AudioBuffer samples
Definition: AudioFile.h:171
bool setAudioBuffer(AudioBuffer &newBuffer)
Definition: AudioFile.h:404
Definition: AudioFile.h:231
static int32_t sampleToThirtyTwoBitInt(T sample)
Definition: AudioFile.h:1401
static T signedByteToSample(int8_t sample)
Definition: AudioFile.h:1557
static T sixteenBitIntToSample(int16_t sample)
Definition: AudioFile.h:1468
static int32_t sampleToTwentyFourBitInt(T sample)
Definition: AudioFile.h:1450
static int16_t sampleToSixteenBitInt(T sample)
Definition: AudioFile.h:1485
static T clamp(T v1, T minValue, T maxValue)
Definition: AudioFile.h:1574
static T thirtyTwoBitIntToSample(int32_t sample)
Definition: AudioFile.h:1384
static uint8_t sampleToUnsignedByte(T sample)
Definition: AudioFile.h:1503
static T twentyFourBitIntToSample(int32_t sample)
Definition: AudioFile.h:1433
static T unsignedByteToSample(uint8_t sample)
Definition: AudioFile.h:1540
static int8_t sampleToSignedByte(T sample)
Definition: AudioFile.h:1522