AudibleT 0.0.1
A real-time A/B/X audio testing tool for subjective assessment of various audio parameters, compatible for general purpose computer as well as embedded systems.
Loading...
Searching...
No Matches
AudioFile.h
Go to the documentation of this file.
1//=======================================================================
29//=======================================================================
30
31#ifndef _AS_AudioFile_h
32#define _AS_AudioFile_h
33
34#if defined (_MSC_VER)
35#undef max
36#undef min
37#define NOMINMAX
38#endif
39
40#include <iostream>
41#include <vector>
42#include <cassert>
43#include <string>
44#include <cstring>
45#include <fstream>
46#include <unordered_map>
47#include <iterator>
48#include <algorithm>
49#include <limits>
50
51// disable some warnings on Windows
52#if defined (_MSC_VER)
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\"")
64#endif
65
66//=============================================================
72{
73 Error,
74 NotLoaded,
75 Wave,
76 Aiff
77};
78
79//=============================================================
80template <class T>
82{
83public:
84
85 //=============================================================
86 typedef std::vector<std::vector<T> > AudioBuffer;
87
88 //=============================================================
91
93 AudioFile (std::string filePath);
94
95 //=============================================================
99 bool load (std::string filePath);
100
104 bool save (std::string filePath, AudioFileFormat format = AudioFileFormat::Wave);
105
106 //=============================================================
108 bool loadFromMemory (std::vector<uint8_t>& fileData);
109
110 //=============================================================
112 uint32_t getSampleRate() const;
113
115 int getNumChannels() const;
116
118 bool isMono() const;
119
121 bool isStereo() const;
122
124 int getBitDepth() const;
125
128
130 double getLengthInSeconds() const;
131
133 void printSummary() const;
134
135 //=============================================================
136
140 bool setAudioBuffer (AudioBuffer& newBuffer);
141
145 void setAudioBufferSize (int numChannels, int numSamples);
146
150 void setNumSamplesPerChannel (int numSamples);
151
153 void setNumChannels (int numChannels);
154
156 void setBitDepth (int numBitsPerSample);
157
159 void setSampleRate (uint32_t newSampleRate);
160
161 //=============================================================
163 void shouldLogErrorsToConsole (bool logErrors);
164
165 //=============================================================
171 AudioBuffer samples;
172
173 //=============================================================
176 std::string iXMLChunk;
177
178private:
179
180 //=============================================================
181 enum class Endianness
182 {
183 LittleEndian,
184 BigEndian
185 };
186
187 //=============================================================
188 AudioFileFormat determineAudioFileFormat (std::vector<uint8_t>& fileData);
189 bool decodeWaveFile (std::vector<uint8_t>& fileData);
190 bool decodeAiffFile (std::vector<uint8_t>& fileData);
191
192 //=============================================================
193 bool saveToWaveFile (std::string filePath);
194 bool saveToAiffFile (std::string filePath);
195
196 //=============================================================
197 void clearAudioBuffer();
198
199 //=============================================================
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);
204
205 //=============================================================
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);
209
210 //=============================================================
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);
214
215 //=============================================================
216 bool writeDataToFile (std::vector<uint8_t>& fileData, std::string filePath);
217
218 //=============================================================
219 void reportError (std::string errorMessage);
220
221 //=============================================================
222 AudioFileFormat audioFileFormat;
223 uint32_t sampleRate;
224 int bitDepth;
225 bool logErrorsToConsole {true};
226};
227
228//=============================================================
229template <typename T>
231{
232 //=============================================================
234 static T signedByteToSample (int8_t sample);
235
237 static int8_t sampleToSignedByte (T sample);
238
239 //=============================================================
241 static T unsignedByteToSample (uint8_t sample);
242
244 static uint8_t sampleToUnsignedByte (T sample);
245
246 //=============================================================
248 static T sixteenBitIntToSample (int16_t sample);
249
251 static int16_t sampleToSixteenBitInt (T sample);
252
253 //=============================================================
255 static T twentyFourBitIntToSample (int32_t sample);
256
258 static int32_t sampleToTwentyFourBitInt (T sample);
259
260 //=============================================================
262 static T thirtyTwoBitIntToSample (int32_t sample);
263
265 static int32_t sampleToThirtyTwoBitInt (T sample);
266
267 //=============================================================
269 static T clamp (T v1, T minValue, T maxValue);
270};
271
272//=============================================================
273// Pre-defined 10-byte representations of common sample rates
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}}
294};
295
296//=============================================================
297enum WavAudioFormat
298{
299 PCM = 0x0001,
300 IEEEFloat = 0x0003,
301 ALaw = 0x0006,
302 MULaw = 0x0007,
303 Extensible = 0xFFFE
304};
305
306//=============================================================
307enum AIFFAudioFormat
308{
309 Uncompressed,
310 Compressed,
311 Error
312};
313
314//=============================================================
315/* IMPLEMENTATION */
316//=============================================================
317
318//=============================================================
319template <class T>
321{
322 bitDepth = 16;
323 sampleRate = 44100;
324 samples.resize (1);
325 samples[0].resize (0);
326 audioFileFormat = AudioFileFormat::NotLoaded;
327}
328
329//=============================================================
330template <class T>
331AudioFile<T>::AudioFile (std::string filePath)
332 : AudioFile<T>()
333{
334 load (filePath);
335}
336
337//=============================================================
338template <class T>
340{
341 return sampleRate;
342}
343
344//=============================================================
345template <class T>
347{
348 return (int)samples.size();
349}
350
351//=============================================================
352template <class T>
354{
355 return getNumChannels() == 1;
356}
357
358//=============================================================
359template <class T>
361{
362 return getNumChannels() == 2;
363}
364
365//=============================================================
366template <class T>
368{
369 return bitDepth;
370}
371
372//=============================================================
373template <class T>
375{
376 if (samples.size() > 0)
377 return (int) samples[0].size();
378 else
379 return 0;
380}
381
382//=============================================================
383template <class T>
385{
386 return (double)getNumSamplesPerChannel() / (double)sampleRate;
387}
388
389//=============================================================
390template <class T>
392{
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;
400}
401
402//=============================================================
403template <class T>
404bool AudioFile<T>::setAudioBuffer (AudioBuffer& newBuffer)
405{
406 int numChannels = (int)newBuffer.size();
407
408 if (numChannels <= 0)
409 {
410 assert (false && "The buffer you are trying to use has no channels");
411 return false;
412 }
413
414 size_t numSamples = newBuffer[0].size();
415
416 // set the number of channels
417 samples.resize (newBuffer.size());
418
419 for (int k = 0; k < getNumChannels(); k++)
420 {
421 assert (newBuffer[k].size() == numSamples);
422
423 samples[k].resize (numSamples);
424
425 for (size_t i = 0; i < numSamples; i++)
426 {
427 samples[k][i] = newBuffer[k][i];
428 }
429 }
430
431 return true;
432}
433
434//=============================================================
435template <class T>
436void AudioFile<T>::setAudioBufferSize (int numChannels, int numSamples)
437{
438 samples.resize (numChannels);
439 setNumSamplesPerChannel (numSamples);
440}
441
442//=============================================================
443template <class T>
445{
446 int originalSize = getNumSamplesPerChannel();
447
448 for (int i = 0; i < getNumChannels();i++)
449 {
450 samples[i].resize (numSamples);
451
452 // set any new samples to zero
453 if (numSamples > originalSize)
454 std::fill (samples[i].begin() + originalSize, samples[i].end(), (T)0.);
455 }
456}
457
458//=============================================================
459template <class T>
460void AudioFile<T>::setNumChannels (int numChannels)
461{
462 int originalNumChannels = getNumChannels();
463 int originalNumSamplesPerChannel = getNumSamplesPerChannel();
464
465 samples.resize (numChannels);
466
467 // make sure any new channels are set to the right size
468 // and filled with zeros
469 if (numChannels > originalNumChannels)
470 {
471 for (int i = originalNumChannels; i < numChannels; i++)
472 {
473 samples[i].resize (originalNumSamplesPerChannel);
474 std::fill (samples[i].begin(), samples[i].end(), (T)0.);
475 }
476 }
477}
478
479//=============================================================
480template <class T>
481void AudioFile<T>::setBitDepth (int numBitsPerSample)
482{
483 bitDepth = numBitsPerSample;
484}
485
486//=============================================================
487template <class T>
488void AudioFile<T>::setSampleRate (uint32_t newSampleRate)
489{
490 sampleRate = newSampleRate;
491}
492
493//=============================================================
494template <class T>
496{
497 logErrorsToConsole = logErrors;
498}
499
500//=============================================================
501template <class T>
502bool AudioFile<T>::load (std::string filePath)
503{
504 std::ifstream file (filePath, std::ios::binary);
505
506 // check the file exists
507 if (! file.good())
508 {
509 reportError ("ERROR: File doesn't exist or otherwise can't load file\n" + filePath);
510 return false;
511 }
512
513 std::vector<uint8_t> fileData;
514
515 file.unsetf (std::ios::skipws);
516
517 file.seekg (0, std::ios::end);
518 size_t length = file.tellg();
519 file.seekg (0, std::ios::beg);
520
521 // allocate
522 fileData.resize (length);
523
524 file.read(reinterpret_cast<char*> (fileData.data()), length);
525 file.close();
526
527 if (file.gcount() != length)
528 {
529 reportError ("ERROR: Couldn't read entire file\n" + filePath);
530 return false;
531 }
532
533 // Handle very small files that will break our attempt to read the
534 // first header info from them
535 if (fileData.size() < 12)
536 {
537 reportError ("ERROR: File is not a valid audio file\n" + filePath);
538 return false;
539 }
540 else
541 {
542 return loadFromMemory (fileData);
543 }
544}
545
546//=============================================================
547template <class T>
548bool AudioFile<T>::loadFromMemory (std::vector<uint8_t>& fileData)
549{
550 // get audio file format
551 audioFileFormat = determineAudioFileFormat (fileData);
552
553 if (audioFileFormat == AudioFileFormat::Wave)
554 {
555 return decodeWaveFile (fileData);
556 }
557 else if (audioFileFormat == AudioFileFormat::Aiff)
558 {
559 return decodeAiffFile (fileData);
560 }
561 else
562 {
563 reportError ("Audio File Type: Error");
564 return false;
565 }
566}
567
568//=============================================================
569template <class T>
570bool AudioFile<T>::decodeWaveFile (std::vector<uint8_t>& fileData)
571{
572 // -----------------------------------------------------------
573 // HEADER CHUNK
574 std::string headerChunkID (fileData.begin(), fileData.begin() + 4);
575 //int32_t fileSizeInBytes = fourBytesToInt (fileData, 4) + 8;
576 std::string format (fileData.begin() + 8, fileData.begin() + 12);
577
578 // -----------------------------------------------------------
579 // try and find the start points of key chunks
580 int indexOfDataChunk = getIndexOfChunk (fileData, "data", 12);
581 int indexOfFormatChunk = getIndexOfChunk (fileData, "fmt ", 12);
582 int indexOfXMLChunk = getIndexOfChunk (fileData, "iXML", 12);
583
584 // if we can't find the data or format chunks, or the IDs/formats don't seem to be as expected
585 // then it is unlikely we'll able to read this file, so abort
586 if (indexOfDataChunk == -1 || indexOfFormatChunk == -1 || headerChunkID != "RIFF" || format != "WAVE")
587 {
588 reportError ("ERROR: this doesn't seem to be a valid .WAV file");
589 return false;
590 }
591
592 // -----------------------------------------------------------
593 // FORMAT CHUNK
594 int f = indexOfFormatChunk;
595 std::string formatChunkID (fileData.begin() + f, fileData.begin() + f + 4);
596 //int32_t formatChunkSize = fourBytesToInt (fileData, 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);
603
604 if (bitDepth > sizeof (T) * 8)
605 {
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);
612 return false;
613 }
614
615 uint16_t numBytesPerSample = static_cast<uint16_t> (bitDepth) / 8;
616
617 // check that the audio format is PCM or Float or extensible
618 if (audioFormat != WavAudioFormat::PCM && audioFormat != WavAudioFormat::IEEEFloat && audioFormat != WavAudioFormat::Extensible)
619 {
620 reportError ("ERROR: this .WAV file is encoded in a format that this library does not support at present");
621 return false;
622 }
623
624 // check the number of channels is mono or stereo
625 if (numChannels < 1 || numChannels > 128)
626 {
627 reportError ("ERROR: this WAV file seems to be an invalid number of channels (or corrupted?)");
628 return false;
629 }
630
631 // check header data is consistent
632 if (numBytesPerSecond != static_cast<uint32_t> ((numChannels * sampleRate * bitDepth) / 8) || numBytesPerBlock != (numChannels * numBytesPerSample))
633 {
634 reportError ("ERROR: the header data in this WAV file seems to be inconsistent");
635 return false;
636 }
637
638 // check bit depth is either 8, 16, 24 or 32 bit
639 if (bitDepth != 8 && bitDepth != 16 && bitDepth != 24 && bitDepth != 32)
640 {
641 reportError ("ERROR: this file has a bit depth that is not 8, 16, 24 or 32 bits");
642 return false;
643 }
644
645 // -----------------------------------------------------------
646 // DATA CHUNK
647 int d = indexOfDataChunk;
648 std::string dataChunkID (fileData.begin() + d, fileData.begin() + d + 4);
649 int32_t dataChunkSize = fourBytesToInt (fileData, d + 4);
650
651 int numSamples = dataChunkSize / (numChannels * bitDepth / 8);
652 int samplesStartIndex = indexOfDataChunk + 8;
653
654 clearAudioBuffer();
655 samples.resize (numChannels);
656
657 for (int i = 0; i < numSamples; i++)
658 {
659 for (int channel = 0; channel < numChannels; channel++)
660 {
661 int sampleIndex = samplesStartIndex + (numBytesPerBlock * i) + channel * numBytesPerSample;
662
663 if ((sampleIndex + (bitDepth / 8) - 1) >= fileData.size())
664 {
665 reportError ("ERROR: read file error as the metadata indicates more samples than there are in the file data");
666 return false;
667 }
668
669 if (bitDepth == 8)
670 {
671 T sample = AudioSampleConverter<T>::unsignedByteToSample (fileData[sampleIndex]);
672 samples[channel].push_back (sample);
673 }
674 else if (bitDepth == 16)
675 {
676 int16_t sampleAsInt = twoBytesToInt (fileData, sampleIndex);
677 T sample = AudioSampleConverter<T>::sixteenBitIntToSample (sampleAsInt);
678 samples[channel].push_back (sample);
679 }
680 else if (bitDepth == 24)
681 {
682 int32_t sampleAsInt = 0;
683 sampleAsInt = (fileData[sampleIndex + 2] << 16) | (fileData[sampleIndex + 1] << 8) | fileData[sampleIndex];
684
685 if (sampleAsInt & 0x800000) // if the 24th bit is set, this is a negative number in 24-bit world
686 sampleAsInt = sampleAsInt | ~0xFFFFFF; // so make sure sign is extended to the 32 bit float
687
689 samples[channel].push_back (sample);
690 }
691 else if (bitDepth == 32)
692 {
693 int32_t sampleAsInt = fourBytesToInt (fileData, sampleIndex);
694 T sample;
695
696 if (audioFormat == WavAudioFormat::IEEEFloat && std::is_floating_point_v<T>)
697 {
698 float f;
699 memcpy (&f, &sampleAsInt, sizeof(int32_t));
700 sample = (T)f;
701 }
702 else // assume PCM
703 {
705 }
706
707 samples[channel].push_back (sample);
708 }
709 else
710 {
711 assert (false);
712 }
713 }
714 }
715
716 // -----------------------------------------------------------
717 // iXML CHUNK
718 if (indexOfXMLChunk != -1)
719 {
720 int32_t chunkSize = fourBytesToInt (fileData, indexOfXMLChunk + 4);
721 iXMLChunk = std::string ((const char*) &fileData[indexOfXMLChunk + 8], chunkSize);
722 }
723
724 return true;
725}
726
727//=============================================================
728template <class T>
729bool AudioFile<T>::decodeAiffFile (std::vector<uint8_t>& fileData)
730{
731 // -----------------------------------------------------------
732 // HEADER CHUNK
733 std::string headerChunkID (fileData.begin(), fileData.begin() + 4);
734 //int32_t fileSizeInBytes = fourBytesToInt (fileData, 4, Endianness::BigEndian) + 8;
735 std::string format (fileData.begin() + 8, fileData.begin() + 12);
736
737 int audioFormat = format == "AIFF" ? AIFFAudioFormat::Uncompressed : format == "AIFC" ? AIFFAudioFormat::Compressed : AIFFAudioFormat::Error;
738
739 // -----------------------------------------------------------
740 // try and find the start points of key chunks
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);
744
745 // if we can't find the data or format chunks, or the IDs/formats don't seem to be as expected
746 // then it is unlikely we'll able to read this file, so abort
747 if (indexOfSoundDataChunk == -1 || indexOfCommChunk == -1 || headerChunkID != "FORM" || audioFormat == AIFFAudioFormat::Error)
748 {
749 reportError ("ERROR: this doesn't seem to be a valid AIFF file");
750 return false;
751 }
752
753 // -----------------------------------------------------------
754 // COMM CHUNK
755 int p = indexOfCommChunk;
756 std::string commChunkID (fileData.begin() + p, fileData.begin() + p + 4);
757 //int32_t commChunkSize = fourBytesToInt (fileData, p + 4, Endianness::BigEndian);
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);
762
763 if (bitDepth > sizeof (T) * 8)
764 {
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);
771 return false;
772 }
773
774 // check the sample rate was properly decoded
775 if (sampleRate == 0)
776 {
777 reportError ("ERROR: this AIFF file has an unsupported sample rate");
778 return false;
779 }
780
781 // check the number of channels is mono or stereo
782 if (numChannels < 1 ||numChannels > 2)
783 {
784 reportError ("ERROR: this AIFF file seems to be neither mono nor stereo (perhaps multi-track, or corrupted?)");
785 return false;
786 }
787
788 // check bit depth is either 8, 16, 24 or 32-bit
789 if (bitDepth != 8 && bitDepth != 16 && bitDepth != 24 && bitDepth != 32)
790 {
791 reportError ("ERROR: this file has a bit depth that is not 8, 16, 24 or 32 bits");
792 return false;
793 }
794
795 // -----------------------------------------------------------
796 // SSND CHUNK
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);
801 //int32_t blockSize = fourBytesToInt (fileData, s + 12, Endianness::BigEndian);
802
803 int numBytesPerSample = bitDepth / 8;
804 int numBytesPerFrame = numBytesPerSample * numChannels;
805 int totalNumAudioSampleBytes = numSamplesPerChannel * numBytesPerFrame;
806 int samplesStartIndex = s + 16 + (int)offset;
807
808 // sanity check the data
809 if ((soundDataChunkSize - 8) != totalNumAudioSampleBytes || totalNumAudioSampleBytes > static_cast<long>(fileData.size() - samplesStartIndex))
810 {
811 reportError ("ERROR: the metadatafor this file doesn't seem right");
812 return false;
813 }
814
815 clearAudioBuffer();
816 samples.resize (numChannels);
817
818 for (int i = 0; i < numSamplesPerChannel; i++)
819 {
820 for (int channel = 0; channel < numChannels; channel++)
821 {
822 int sampleIndex = samplesStartIndex + (numBytesPerFrame * i) + channel * numBytesPerSample;
823
824 if ((sampleIndex + (bitDepth / 8) - 1) >= fileData.size())
825 {
826 reportError ("ERROR: read file error as the metadata indicates more samples than there are in the file data");
827 return false;
828 }
829
830 if (bitDepth == 8)
831 {
832 T sample = AudioSampleConverter<T>::signedByteToSample (static_cast<int8_t> (fileData[sampleIndex]));
833 samples[channel].push_back (sample);
834 }
835 else if (bitDepth == 16)
836 {
837 int16_t sampleAsInt = twoBytesToInt (fileData, sampleIndex, Endianness::BigEndian);
838 T sample = AudioSampleConverter<T>::sixteenBitIntToSample (sampleAsInt);
839 samples[channel].push_back (sample);
840 }
841 else if (bitDepth == 24)
842 {
843 int32_t sampleAsInt = 0;
844 sampleAsInt = (fileData[sampleIndex] << 16) | (fileData[sampleIndex + 1] << 8) | fileData[sampleIndex + 2];
845
846 if (sampleAsInt & 0x800000) // if the 24th bit is set, this is a negative number in 24-bit world
847 sampleAsInt = sampleAsInt | ~0xFFFFFF; // so make sure sign is extended to the 32 bit float
848
850 samples[channel].push_back (sample);
851 }
852 else if (bitDepth == 32)
853 {
854 int32_t sampleAsInt = fourBytesToInt (fileData, sampleIndex, Endianness::BigEndian);
855 T sample;
856
857 if (audioFormat == AIFFAudioFormat::Compressed)
858 sample = (T)reinterpret_cast<float&> (sampleAsInt);
859 else // assume PCM
861
862 samples[channel].push_back (sample);
863 }
864 else
865 {
866 assert (false);
867 }
868 }
869 }
870
871 // -----------------------------------------------------------
872 // iXML CHUNK
873 if (indexOfXMLChunk != -1)
874 {
875 int32_t chunkSize = fourBytesToInt (fileData, indexOfXMLChunk + 4);
876 iXMLChunk = std::string ((const char*) &fileData[indexOfXMLChunk + 8], chunkSize);
877 }
878
879 return true;
880}
881
882//=============================================================
883template <class T>
884uint32_t AudioFile<T>::getAiffSampleRate (std::vector<uint8_t>& fileData, int sampleRateStartIndex)
885{
886 for (auto it : aiffSampleRateTable)
887 {
888 if (tenByteMatch (fileData, sampleRateStartIndex, it.second, 0))
889 return it.first;
890 }
891
892 return 0;
893}
894
895//=============================================================
896template <class T>
897bool AudioFile<T>::tenByteMatch (std::vector<uint8_t>& v1, int startIndex1, std::vector<uint8_t>& v2, int startIndex2)
898{
899 for (int i = 0; i < 10; i++)
900 {
901 if (v1[startIndex1 + i] != v2[startIndex2 + i])
902 return false;
903 }
904
905 return true;
906}
907
908//=============================================================
909template <class T>
910void AudioFile<T>::addSampleRateToAiffData (std::vector<uint8_t>& fileData, uint32_t sampleRate)
911{
912 if (aiffSampleRateTable.count (sampleRate) > 0)
913 {
914 for (int i = 0; i < 10; i++)
915 fileData.push_back (aiffSampleRateTable[sampleRate][i]);
916 }
917}
918
919//=============================================================
920template <class T>
921bool AudioFile<T>::save (std::string filePath, AudioFileFormat format)
922{
923 if (format == AudioFileFormat::Wave)
924 {
925 return saveToWaveFile (filePath);
926 }
927 else if (format == AudioFileFormat::Aiff)
928 {
929 return saveToAiffFile (filePath);
930 }
931
932 return false;
933}
934
935//=============================================================
936template <class T>
937bool AudioFile<T>::saveToWaveFile (std::string filePath)
938{
939 std::vector<uint8_t> fileData;
940
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());
945
946 // -----------------------------------------------------------
947 // HEADER CHUNK
948 addStringToFileData (fileData, "RIFF");
949
950 // The file size in bytes is the header chunk size (4, not counting RIFF and WAVE) + the format
951 // chunk size (24) + the metadata part of the data chunk plus the actual data chunk size
952 int32_t fileSizeInBytes = 4 + formatChunkSize + 8 + 8 + dataChunkSize;
953 if (iXMLChunkSize > 0)
954 {
955 fileSizeInBytes += (8 + iXMLChunkSize);
956 }
957
958 addInt32ToFileData (fileData, fileSizeInBytes);
959
960 addStringToFileData (fileData, "WAVE");
961
962 // -----------------------------------------------------------
963 // FORMAT CHUNK
964 addStringToFileData (fileData, "fmt ");
965 addInt32ToFileData (fileData, formatChunkSize); // format chunk size (16 for PCM)
966 addInt16ToFileData (fileData, audioFormat); // audio format
967 addInt16ToFileData (fileData, (int16_t)getNumChannels()); // num channels
968 addInt32ToFileData (fileData, (int32_t)sampleRate); // sample rate
969
970 int32_t numBytesPerSecond = (int32_t) ((getNumChannels() * sampleRate * bitDepth) / 8);
971 addInt32ToFileData (fileData, numBytesPerSecond);
972
973 int16_t numBytesPerBlock = getNumChannels() * (bitDepth / 8);
974 addInt16ToFileData (fileData, numBytesPerBlock);
975
976 addInt16ToFileData (fileData, (int16_t)bitDepth);
977
978 if (audioFormat == WavAudioFormat::IEEEFloat)
979 addInt16ToFileData (fileData, 0); // extension size
980
981 // -----------------------------------------------------------
982 // DATA CHUNK
983 addStringToFileData (fileData, "data");
984 addInt32ToFileData (fileData, dataChunkSize);
985
986 for (int i = 0; i < getNumSamplesPerChannel(); i++)
987 {
988 for (int channel = 0; channel < getNumChannels(); channel++)
989 {
990 if (bitDepth == 8)
991 {
992 uint8_t byte = AudioSampleConverter<T>::sampleToUnsignedByte (samples[channel][i]);
993 fileData.push_back (byte);
994 }
995 else if (bitDepth == 16)
996 {
997 int16_t sampleAsInt = AudioSampleConverter<T>::sampleToSixteenBitInt (samples[channel][i]);
998 addInt16ToFileData (fileData, sampleAsInt);
999 }
1000 else if (bitDepth == 24)
1001 {
1002 int32_t sampleAsIntAgain = AudioSampleConverter<T>::sampleToTwentyFourBitInt (samples[channel][i]);
1003
1004 uint8_t bytes[3];
1005 bytes[2] = (uint8_t) (sampleAsIntAgain >> 16) & 0xFF;
1006 bytes[1] = (uint8_t) (sampleAsIntAgain >> 8) & 0xFF;
1007 bytes[0] = (uint8_t) sampleAsIntAgain & 0xFF;
1008
1009 fileData.push_back (bytes[0]);
1010 fileData.push_back (bytes[1]);
1011 fileData.push_back (bytes[2]);
1012 }
1013 else if (bitDepth == 32)
1014 {
1015 int32_t sampleAsInt;
1016
1017 if (audioFormat == WavAudioFormat::IEEEFloat)
1018 sampleAsInt = (int32_t) reinterpret_cast<int32_t&> (samples[channel][i]);
1019 else // assume PCM
1020 sampleAsInt = AudioSampleConverter<T>::sampleToThirtyTwoBitInt (samples[channel][i]);
1021
1022 addInt32ToFileData (fileData, sampleAsInt, Endianness::LittleEndian);
1023 }
1024 else
1025 {
1026 assert (false && "Trying to write a file with unsupported bit depth");
1027 return false;
1028 }
1029 }
1030 }
1031
1032 // -----------------------------------------------------------
1033 // iXML CHUNK
1034 if (iXMLChunkSize > 0)
1035 {
1036 addStringToFileData (fileData, "iXML");
1037 addInt32ToFileData (fileData, iXMLChunkSize);
1038 addStringToFileData (fileData, iXMLChunk);
1039 }
1040
1041 // check that the various sizes we put in the metadata are correct
1042 if (fileSizeInBytes != static_cast<int32_t> (fileData.size() - 8) || dataChunkSize != (getNumSamplesPerChannel() * getNumChannels() * (bitDepth / 8)))
1043 {
1044 reportError ("ERROR: couldn't save file to " + filePath);
1045 return false;
1046 }
1047
1048 // try to write the file
1049 return writeDataToFile (fileData, filePath);
1050}
1051
1052//=============================================================
1053template <class T>
1054bool AudioFile<T>::saveToAiffFile (std::string filePath)
1055{
1056 std::vector<uint8_t> fileData;
1057
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());
1063
1064 // -----------------------------------------------------------
1065 // HEADER CHUNK
1066 addStringToFileData (fileData, "FORM");
1067
1068 // The file size in bytes is the header chunk size (4, not counting FORM and AIFF) + the COMM
1069 // chunk size (26) + the metadata part of the SSND chunk plus the actual data chunk size
1070 int32_t fileSizeInBytes = 4 + 26 + 16 + totalNumAudioSampleBytes;
1071 if (iXMLChunkSize > 0)
1072 {
1073 fileSizeInBytes += (8 + iXMLChunkSize);
1074 }
1075
1076 addInt32ToFileData (fileData, fileSizeInBytes, Endianness::BigEndian);
1077
1078 addStringToFileData (fileData, "AIFF");
1079
1080 // -----------------------------------------------------------
1081 // COMM CHUNK
1082 addStringToFileData (fileData, "COMM");
1083 addInt32ToFileData (fileData, 18, Endianness::BigEndian); // commChunkSize
1084 addInt16ToFileData (fileData, getNumChannels(), Endianness::BigEndian); // num channels
1085 addInt32ToFileData (fileData, getNumSamplesPerChannel(), Endianness::BigEndian); // num samples per channel
1086 addInt16ToFileData (fileData, bitDepth, Endianness::BigEndian); // bit depth
1087 addSampleRateToAiffData (fileData, sampleRate);
1088
1089 // -----------------------------------------------------------
1090 // SSND CHUNK
1091 addStringToFileData (fileData, "SSND");
1092 addInt32ToFileData (fileData, soundDataChunkSize, Endianness::BigEndian);
1093 addInt32ToFileData (fileData, 0, Endianness::BigEndian); // offset
1094 addInt32ToFileData (fileData, 0, Endianness::BigEndian); // block size
1095
1096 for (int i = 0; i < getNumSamplesPerChannel(); i++)
1097 {
1098 for (int channel = 0; channel < getNumChannels(); channel++)
1099 {
1100 if (bitDepth == 8)
1101 {
1102 uint8_t byte = static_cast<uint8_t> (AudioSampleConverter<T>::sampleToSignedByte (samples[channel][i]));
1103 fileData.push_back (byte);
1104 }
1105 else if (bitDepth == 16)
1106 {
1107 int16_t sampleAsInt = AudioSampleConverter<T>::sampleToSixteenBitInt (samples[channel][i]);
1108 addInt16ToFileData (fileData, sampleAsInt, Endianness::BigEndian);
1109 }
1110 else if (bitDepth == 24)
1111 {
1112 int32_t sampleAsIntAgain = AudioSampleConverter<T>::sampleToTwentyFourBitInt (samples[channel][i]);
1113
1114 uint8_t bytes[3];
1115 bytes[0] = (uint8_t) (sampleAsIntAgain >> 16) & 0xFF;
1116 bytes[1] = (uint8_t) (sampleAsIntAgain >> 8) & 0xFF;
1117 bytes[2] = (uint8_t) sampleAsIntAgain & 0xFF;
1118
1119 fileData.push_back (bytes[0]);
1120 fileData.push_back (bytes[1]);
1121 fileData.push_back (bytes[2]);
1122 }
1123 else if (bitDepth == 32)
1124 {
1125 // write samples as signed integers (no implementation yet for floating point, but looking at WAV implementation should help)
1126 int32_t sampleAsInt = AudioSampleConverter<T>::sampleToThirtyTwoBitInt (samples[channel][i]);
1127 addInt32ToFileData (fileData, sampleAsInt, Endianness::BigEndian);
1128 }
1129 else
1130 {
1131 assert (false && "Trying to write a file with unsupported bit depth");
1132 return false;
1133 }
1134 }
1135 }
1136
1137 // -----------------------------------------------------------
1138 // iXML CHUNK
1139 if (iXMLChunkSize > 0)
1140 {
1141 addStringToFileData (fileData, "iXML");
1142 addInt32ToFileData (fileData, iXMLChunkSize, Endianness::BigEndian);
1143 addStringToFileData (fileData, iXMLChunk);
1144 }
1145
1146 // check that the various sizes we put in the metadata are correct
1147 if (fileSizeInBytes != static_cast<int32_t> (fileData.size() - 8) || soundDataChunkSize != getNumSamplesPerChannel() * numBytesPerFrame + 8)
1148 {
1149 reportError ("ERROR: couldn't save file to " + filePath);
1150 return false;
1151 }
1152
1153 // try to write the file
1154 return writeDataToFile (fileData, filePath);
1155}
1156
1157//=============================================================
1158template <class T>
1159bool AudioFile<T>::writeDataToFile (std::vector<uint8_t>& fileData, std::string filePath)
1160{
1161 std::ofstream outputFile (filePath, std::ios::binary);
1162
1163 if (outputFile.is_open())
1164 {
1165 for (size_t i = 0; i < fileData.size(); i++)
1166 {
1167 char value = (char) fileData[i];
1168 outputFile.write (&value, sizeof (char));
1169 }
1170
1171 outputFile.close();
1172
1173 return true;
1174 }
1175
1176 return false;
1177}
1178
1179//=============================================================
1180template <class T>
1181void AudioFile<T>::addStringToFileData (std::vector<uint8_t>& fileData, std::string s)
1182{
1183 for (size_t i = 0; i < s.length();i++)
1184 fileData.push_back ((uint8_t) s[i]);
1185}
1186
1187//=============================================================
1188template <class T>
1189void AudioFile<T>::addInt32ToFileData (std::vector<uint8_t>& fileData, int32_t i, Endianness endianness)
1190{
1191 uint8_t bytes[4];
1192
1193 if (endianness == Endianness::LittleEndian)
1194 {
1195 bytes[3] = (i >> 24) & 0xFF;
1196 bytes[2] = (i >> 16) & 0xFF;
1197 bytes[1] = (i >> 8) & 0xFF;
1198 bytes[0] = i & 0xFF;
1199 }
1200 else
1201 {
1202 bytes[0] = (i >> 24) & 0xFF;
1203 bytes[1] = (i >> 16) & 0xFF;
1204 bytes[2] = (i >> 8) & 0xFF;
1205 bytes[3] = i & 0xFF;
1206 }
1207
1208 for (int i = 0; i < 4; i++)
1209 fileData.push_back (bytes[i]);
1210}
1211
1212//=============================================================
1213template <class T>
1214void AudioFile<T>::addInt16ToFileData (std::vector<uint8_t>& fileData, int16_t i, Endianness endianness)
1215{
1216 uint8_t bytes[2];
1217
1218 if (endianness == Endianness::LittleEndian)
1219 {
1220 bytes[1] = (i >> 8) & 0xFF;
1221 bytes[0] = i & 0xFF;
1222 }
1223 else
1224 {
1225 bytes[0] = (i >> 8) & 0xFF;
1226 bytes[1] = i & 0xFF;
1227 }
1228
1229 fileData.push_back (bytes[0]);
1230 fileData.push_back (bytes[1]);
1231}
1232
1233//=============================================================
1234template <class T>
1236{
1237 for (size_t i = 0; i < samples.size();i++)
1238 {
1239 samples[i].clear();
1240 }
1241
1242 samples.clear();
1243}
1244
1245//=============================================================
1246template <class T>
1247AudioFileFormat AudioFile<T>::determineAudioFileFormat (std::vector<uint8_t>& fileData)
1248{
1249 std::string header (fileData.begin(), fileData.begin() + 4);
1250
1251 if (header == "RIFF")
1252 return AudioFileFormat::Wave;
1253 else if (header == "FORM")
1254 return AudioFileFormat::Aiff;
1255 else
1256 return AudioFileFormat::Error;
1257}
1258
1259//=============================================================
1260template <class T>
1261int32_t AudioFile<T>::fourBytesToInt (std::vector<uint8_t>& source, int startIndex, Endianness endianness)
1262{
1263 if (source.size() >= (startIndex + 4))
1264 {
1265 int32_t result;
1266
1267 if (endianness == Endianness::LittleEndian)
1268 result = (source[startIndex + 3] << 24) | (source[startIndex + 2] << 16) | (source[startIndex + 1] << 8) | source[startIndex];
1269 else
1270 result = (source[startIndex] << 24) | (source[startIndex + 1] << 16) | (source[startIndex + 2] << 8) | source[startIndex + 3];
1271
1272 return result;
1273 }
1274 else
1275 {
1276 assert (false && "Attempted to read four bytes from vector at position where out of bounds access would occur");
1277 return 0; // this is a dummy value as we don't have one to return
1278 }
1279}
1280
1281//=============================================================
1282template <class T>
1283int16_t AudioFile<T>::twoBytesToInt (std::vector<uint8_t>& source, int startIndex, Endianness endianness)
1284{
1285 int16_t result;
1286
1287 if (endianness == Endianness::LittleEndian)
1288 result = (source[startIndex + 1] << 8) | source[startIndex];
1289 else
1290 result = (source[startIndex] << 8) | source[startIndex + 1];
1291
1292 return result;
1293}
1294
1295//=============================================================
1296template <class T>
1297int AudioFile<T>::getIndexOfString (std::vector<uint8_t>& source, std::string stringToSearchFor)
1298{
1299 int index = -1;
1300 int stringLength = (int)stringToSearchFor.length();
1301
1302 for (size_t i = 0; i < source.size() - stringLength;i++)
1303 {
1304 std::string section (source.begin() + i, source.begin() + i + stringLength);
1305
1306 if (section == stringToSearchFor)
1307 {
1308 index = static_cast<int> (i);
1309 break;
1310 }
1311 }
1312
1313 return index;
1314}
1315
1316//=============================================================
1317template <class T>
1318int AudioFile<T>::getIndexOfChunk (std::vector<uint8_t>& source, const std::string& chunkHeaderID, int startIndex, Endianness endianness)
1319{
1320 constexpr int dataLen = 4;
1321
1322 if (chunkHeaderID.size() != dataLen)
1323 {
1324 assert (false && "Invalid chunk header ID string");
1325 return -1;
1326 }
1327
1328 int i = startIndex;
1329 while (i < source.size() - dataLen)
1330 {
1331 if (memcmp (&source[i], chunkHeaderID.data(), dataLen) == 0)
1332 {
1333 return i;
1334 }
1335
1336 i += dataLen;
1337
1338 // If somehow we don't have 4 bytes left to read, then exit with -1
1339 if ((i + 4) >= source.size())
1340 return -1;
1341
1342 auto chunkSize = fourBytesToInt (source, i, endianness);
1343 i += (dataLen + chunkSize);
1344 }
1345
1346 return -1;
1347}
1348
1349//=============================================================
1350template <class T>
1351void AudioFile<T>::reportError (std::string errorMessage)
1352{
1353 if (logErrorsToConsole)
1354 std::cout << errorMessage << std::endl;
1355}
1356
1357//=============================================================
1358template <typename SignedType>
1359typename std::make_unsigned<SignedType>::type convertSignedToUnsigned (SignedType signedValue)
1360{
1361 static_assert (std::is_signed<SignedType>::value, "The input value must be signed");
1362
1363 typename std::make_unsigned<SignedType>::type unsignedValue = static_cast<typename std::make_unsigned<SignedType>::type> (1) + std::numeric_limits<SignedType>::max();
1364
1365 unsignedValue += signedValue;
1366 return unsignedValue;
1367}
1368
1369//=============================================================
1370enum SampleLimit
1371{
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
1380};
1381
1382//=============================================================
1383template <class T>
1385{
1386 if constexpr (std::is_floating_point<T>::value)
1387 {
1388 return static_cast<T> (sample) / static_cast<T> (std::numeric_limits<int32_t>::max());
1389 }
1390 else if (std::numeric_limits<T>::is_integer)
1391 {
1392 if constexpr (std::is_signed_v<T>)
1393 return static_cast<T> (sample);
1394 else
1395 return static_cast<T> (clamp (static_cast<T> (sample + 2147483648), 0, 4294967295));
1396 }
1397}
1398
1399//=============================================================
1400template <class T>
1402{
1403 if constexpr (std::is_floating_point<T>::value)
1404 {
1405 // multiplying a float by a the max int32_t is problematic because
1406 // of roundng errors which can cause wrong values to come out, so
1407 // we use a different implementation here compared to other types
1408 if constexpr (std::is_same_v<T, float>)
1409 {
1410 if (sample >= 1.f)
1411 return std::numeric_limits<int32_t>::max();
1412 else if (sample <= -1.f)
1413 return std::numeric_limits<int32_t>::lowest() + 1; // starting at 1 preserves symmetry
1414 else
1415 return static_cast<int32_t> (sample * std::numeric_limits<int32_t>::max());
1416 }
1417 else
1418 {
1419 return static_cast<int32_t> (clamp (sample, -1., 1.) * std::numeric_limits<int32_t>::max());
1420 }
1421 }
1422 else
1423 {
1424 if constexpr (std::is_signed_v<T>)
1425 return static_cast<int32_t> (clamp (sample, -2147483648LL, 2147483647LL));
1426 else
1427 return static_cast<int32_t> (clamp (sample, 0, 4294967295) - 2147483648);
1428 }
1429}
1430
1431//=============================================================
1432template <class T>
1434{
1435 if constexpr (std::is_floating_point<T>::value)
1436 {
1437 return static_cast<T> (sample) / static_cast<T> (8388607.);
1438 }
1439 else if (std::numeric_limits<T>::is_integer)
1440 {
1441 if constexpr (std::is_signed_v<T>)
1442 return static_cast<T> (clamp (sample, SignedInt24_Min, SignedInt24_Max));
1443 else
1444 return static_cast<T> (clamp (sample + 8388608, UnsignedInt24_Min, UnsignedInt24_Max));
1445 }
1446}
1447
1448//=============================================================
1449template <class T>
1451{
1452 if constexpr (std::is_floating_point<T>::value)
1453 {
1454 sample = clamp (sample, -1., 1.);
1455 return static_cast<int32_t> (sample * 8388607.);
1456 }
1457 else
1458 {
1459 if constexpr (std::is_signed_v<T>)
1460 return static_cast<int32_t> (clamp (sample, SignedInt24_Min, SignedInt24_Max));
1461 else
1462 return static_cast<int32_t> (clamp (sample, UnsignedInt24_Min, UnsignedInt24_Max) + SignedInt24_Min);
1463 }
1464}
1465
1466//=============================================================
1467template <class T>
1469{
1470 if constexpr (std::is_floating_point<T>::value)
1471 {
1472 return static_cast<T> (sample) / static_cast<T> (32767.);
1473 }
1474 else if constexpr (std::numeric_limits<T>::is_integer)
1475 {
1476 if constexpr (std::is_signed_v<T>)
1477 return static_cast<T> (sample);
1478 else
1479 return static_cast<T> (convertSignedToUnsigned<int16_t> (sample));
1480 }
1481}
1482
1483//=============================================================
1484template <class T>
1486{
1487 if constexpr (std::is_floating_point<T>::value)
1488 {
1489 sample = clamp (sample, -1., 1.);
1490 return static_cast<int16_t> (sample * 32767.);
1491 }
1492 else
1493 {
1494 if constexpr (std::is_signed_v<T>)
1495 return static_cast<int16_t> (clamp (sample, SignedInt16_Min, SignedInt16_Max));
1496 else
1497 return static_cast<int16_t> (clamp (sample, UnsignedInt16_Min, UnsignedInt16_Max) + SignedInt16_Min);
1498 }
1499}
1500
1501//=============================================================
1502template <class T>
1504{
1505 if constexpr (std::is_floating_point<T>::value)
1506 {
1507 sample = clamp (sample, -1., 1.);
1508 sample = (sample + 1.) / 2.;
1509 return static_cast<uint8_t> (1 + (sample * 254));
1510 }
1511 else
1512 {
1513 if constexpr (std::is_signed_v<T>)
1514 return static_cast<uint8_t> (clamp (sample, -128, 127) + 128);
1515 else
1516 return static_cast<uint8_t> (clamp (sample, 0, 255));
1517 }
1518}
1519
1520//=============================================================
1521template <class T>
1523{
1524 if constexpr (std::is_floating_point<T>::value)
1525 {
1526 sample = clamp (sample, -1., 1.);
1527 return static_cast<int8_t> (sample * (T)0x7F);
1528 }
1529 else
1530 {
1531 if constexpr (std::is_signed_v<T>)
1532 return static_cast<int8_t> (clamp (sample, -128, 127));
1533 else
1534 return static_cast<int8_t> (clamp (sample, 0, 255) - 128);
1535 }
1536}
1537
1538//=============================================================
1539template <class T>
1541{
1542 if constexpr (std::is_floating_point<T>::value)
1543 {
1544 return static_cast<T> (sample - 128) / static_cast<T> (127.);
1545 }
1546 else if (std::numeric_limits<T>::is_integer)
1547 {
1548 if constexpr (std::is_unsigned_v<T>)
1549 return static_cast<T> (sample);
1550 else
1551 return static_cast<T> (sample - 128);
1552 }
1553}
1554
1555//=============================================================
1556template <class T>
1558{
1559 if constexpr (std::is_floating_point<T>::value)
1560 {
1561 return static_cast<T> (sample) / static_cast<T> (127.);
1562 }
1563 else if constexpr (std::numeric_limits<T>::is_integer)
1564 {
1565 if constexpr (std::is_signed_v<T>)
1566 return static_cast<T> (sample);
1567 else
1568 return static_cast<T> (convertSignedToUnsigned<int8_t> (sample));
1569 }
1570}
1571
1572//=============================================================
1573template <class T>
1574T AudioSampleConverter<T>::clamp (T value, T minValue, T maxValue)
1575{
1576 value = std::min (value, maxValue);
1577 value = std::max (value, minValue);
1578 return value;
1579}
1580
1581#if defined (_MSC_VER)
1582 __pragma(warning (pop))
1583#elif defined (__GNUC__)
1584 _Pragma("GCC diagnostic pop")
1585#endif
1586
1587#endif /* AudioFile_h */
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