29static const char*
const aiffFormatName =
"AIFF file";
42namespace AiffFileHelpers
47 #pragma pack (push, 1)
101 static void create (MemoryBlock&
block,
const StringPairArray& values)
103 if (values.getAllKeys().contains (
"MidiUnityNote",
true))
105 block.setSize ((
sizeof (InstChunk) + 3) & ~(
size_t) 3,
true);
106 auto&
inst = *
static_cast<InstChunk*
> (
block.getData());
108 inst.baseNote = getValue8 (values,
"MidiUnityNote",
"60");
109 inst.detune = getValue8 (values,
"Detune",
"0");
110 inst.lowNote = getValue8 (values,
"LowNote",
"0");
111 inst.highNote = getValue8 (values,
"HighNote",
"127");
112 inst.lowVelocity = getValue8 (values,
"LowVelocity",
"1");
113 inst.highVelocity = getValue8 (values,
"HighVelocity",
"127");
114 inst.gain = (
int16) getValue16 (values,
"Gain",
"0");
116 inst.sustainLoop.type = getValue16 (values,
"Loop0Type",
"0");
117 inst.sustainLoop.startIdentifier = getValue16 (values,
"Loop0StartIdentifier",
"0");
118 inst.sustainLoop.endIdentifier = getValue16 (values,
"Loop0EndIdentifier",
"0");
119 inst.releaseLoop.type = getValue16 (values,
"Loop1Type",
"0");
120 inst.releaseLoop.startIdentifier = getValue16 (values,
"Loop1StartIdentifier",
"0");
121 inst.releaseLoop.endIdentifier = getValue16 (values,
"Loop1EndIdentifier",
"0");
149 input.
read (unknown,
sizeof (unknown));
172 case neither:
keyString =
"neither";
break;
205 static bool isValidTag (
const char* d)
noexcept
212 static bool isAppleGenre (
const String& tag)
noexcept
235 static String
read (InputStream& input,
const uint32 length)
238 input.skipNextBytes (4);
239 input.readIntoMemoryBlock (
mb, (ssize_t) length - 4);
243 auto*
data =
static_cast<const char*
> (
mb.getData());
250 if (isValidTag (data))
252 auto tag = String (CharPointer_UTF8 (data), CharPointer_UTF8 (
dataEnd));
259 if (data <
dataEnd && data[0] == 0)
261 if (data + 52 <
dataEnd && isValidTag (data + 50))
data += 50;
262 else if (data + 120 <
dataEnd && isValidTag (data + 118))
data += 118;
263 else if (data + 170 <
dataEnd && isValidTag (data + 168))
data += 168;
274 static bool metaDataContainsZeroIdentifiers (
const StringPairArray& values)
281 for (
auto& key : values.getAllKeys())
287 if (values.getValue (key,
"-1").getIntValue() == 0)
294 static void create (MemoryBlock&
block,
const StringPairArray& values)
296 auto numCues = values.getValue (
"NumCuePoints",
"0").getIntValue();
300 MemoryOutputStream out (
block,
false);
301 out.writeShortBigEndian ((
short) numCues);
303 auto numCueLabels = values.getValue (
"NumCueLabels",
"0").getIntValue();
304 auto idOffset = metaDataContainsZeroIdentifiers (values) ? 1 : 0;
310 for (
int i = 0; i < numCues; ++i)
313 auto identifier =
idOffset + values.getValue (
prefixCue +
"Identifier",
"1").getIntValue();
320 auto offset = values.getValue (
prefixCue +
"Offset",
"0").getIntValue();
321 auto label =
"CueLabel" + String (i);
330 label = values.getValue (
prefixLabel +
"Text", label);
335 out.writeShortBigEndian ((
short) identifier);
336 out.writeIntBigEndian (offset);
339 out.writeByte (
static_cast<char> (
labelLength + 1));
343 if ((out.getDataSize() & 1) != 0)
353 static void create (MemoryBlock&
block,
const StringPairArray& values)
355 auto numNotes = values.getValue (
"NumCueNotes",
"0").getIntValue();
359 MemoryOutputStream out (
block,
false);
360 out.writeShortBigEndian ((
short)
numNotes);
364 auto prefix =
"CueNote" + String (i);
366 out.writeIntBigEndian (values.getValue (prefix +
"TimeStamp",
"0").getIntValue());
367 out.writeShortBigEndian ((
short) values.getValue (prefix +
"Identifier",
"0").getIntValue());
369 auto comment = values.getValue (prefix +
"Text", String());
372 out.writeShortBigEndian (
static_cast<short> (
commentLength + 1));
376 if ((out.getDataSize() & 1) != 0)
391 using namespace AiffFileHelpers;
422 if (type == chunkName (
"FVER"))
427 if (
ver != 0 &&
ver != (
int) 0xa2805140)
430 else if (type == chunkName (
"COMM"))
443 if ((
byte0 & 0x80) != 0
456 littleEndian =
false;
464 littleEndian =
false;
466 else if (
compType == chunkName (
"sowt"))
472 littleEndian =
false;
482 else if (type == chunkName (
"SSND"))
490 else if (type == chunkName (
"MARK"))
498 for (
uint16 i = 0; i < numCues; ++i)
521 else if (type == chunkName (
"COMT"))
535 auto prefix =
"CueNote" +
String (i);
541 else if (type == chunkName (
"INST"))
548 else if (type == chunkName (
"basc"))
552 else if (type == chunkName (
"cate"))
555 AiffFileHelpers::CATEChunk::read (*
input, length));
587 while (numSamples > 0)
617 template <
typename Endianness>
620 const void*
sourceData,
int numberOfChannels,
int numSamples)
noexcept
635 int64 dataChunkStart;
647 unsigned int numChans,
unsigned int bits,
651 using namespace AiffFileHelpers;
653 if (metadataValues.
size() > 0)
660 MarkChunk::create (markChunk, metadataValues);
661 COMTChunk::create (comtChunk, metadataValues);
662 InstChunk::create (instChunk, metadataValues);
671 if ((bytesWritten & 1) != 0)
678 bool write (
const int** data,
int numSamples)
override
681 jassert (data !=
nullptr && *data !=
nullptr);
698 if (bytesWritten + bytes >= (
size_t) 0xfff00000
709 bytesWritten += bytes;
710 lengthInSamples += (
uint64) numSamples;
715 MemoryBlock tempBlock, markChunk, comtChunk, instChunk;
716 uint64 lengthInSamples = 0, bytesWritten = 0;
717 int64 headerPosition = 0;
718 bool writeFailed =
false;
722 using namespace AiffFileHelpers;
731 + (comtChunk.isEmpty() ? 0 : comtChunk.getSize() + 8)
732 + (instChunk.isEmpty() ? 0 : instChunk.getSize() + 8));
755 int mask = 0x40000000;
768 for (i = 0; i <= 32 ; ++i)
827 littleEndian (reader.littleEndian)
847 AiffAudioFormatReader::copySampleData<AudioData::LittleEndian>
851 AiffAudioFormatReader::copySampleData<AudioData::BigEndian>
862 if (map ==
nullptr || ! mappedSection.
contains (sample))
866 zeromem (result, (
size_t) num *
sizeof (
float));
870 float** dest = &result;
930 const bool littleEndian;
932 template <
typename SampleType>
939 template <
typename SampleType>
955 return { 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000 };
960 return { 8, 16, 24 };
975 return type == 0x41494646 || type == 0x41494643
976 || type == 0x61696666 || type == 0x61696663 ;
984 if (w->sampleRate > 0 && w->numChannels > 0)
1013 unsigned int numberOfChannels,
1020 (
unsigned int) bitsPerSample, metadataValues);
Holds a resizable array of primitive or copy-by-value objects.
static constexpr uint32 bigEndianInt(const void *bytes) noexcept
Turns 4 bytes into a big-endian integer.
static constexpr uint32 littleEndianInt(const void *bytes) noexcept
Turns 4 bytes into a little-endian integer.
static Type swapIfLittleEndian(Type value) noexcept
Swaps the byte order of a signed or unsigned integer if the CPU is little-endian.
static constexpr uint16 bigEndianShort(const void *bytes) noexcept
Turns 2 bytes into a big-endian integer.
static bool isLowerCase(juce_wchar character) noexcept
Checks whether a unicode character is lower-case.
static bool isLetterOrDigit(char character) noexcept
Checks whether a character is alphabetic or numeric.
static bool isUpperCase(juce_wchar character) noexcept
Checks whether a unicode character is upper-case.
Represents a local file or directory.
OSType getMacOSType() const
OSX ONLY - Finds the OSType of a file from the its resources.
std::unique_ptr< FileInputStream > createInputStream() const
Creates a stream to read from this file.
Very simple container class to hold a pointer to some data on the heap.
void calloc(SizeType newNumElements, const size_t elementSize=sizeof(ElementType))
Allocates a specified amount of memory and clears it.
A class to hold a resizable block of raw data.
bool isEmpty() const noexcept
Returns true if the memory block has zero size.
void * getData() noexcept
Returns a void pointer to the data.
size_t getSize() const noexcept
Returns the block's current allocated size, in bytes.
void ensureSize(size_t minimumSize, bool initialiseNewSpaceToZero=false)
Increases the block's size only if it's smaller than a given size.
void readMaxLevels(int64 startSampleInFile, int64 numSamples, Range< float > *results, int numChannelsToRead) override
Finds the highest and lowest sample levels from a section of the audio stream.
bool readSamples(int *const *destSamples, int numDestChannels, int startOffsetInDestBuffer, int64 startSampleInFile, int numSamples) override
Subclasses must implement this method to perform the low-level read operation.
void getSample(int64 sample, float *result) const noexcept override
Returns the samples for all channels at a given sample position.
The base class for streams that write data to some kind of destination.
virtual bool write(const void *dataToWrite, size_t numberOfBytes)=0
Writes a block of data to the stream.
virtual int64 getPosition()=0
Returns the stream's current position.
virtual bool writeByte(char byte)
Writes a single byte to the stream.
virtual bool writeIntBigEndian(int value)
Writes a 32-bit integer to the stream in a big-endian byte order.
virtual bool setPosition(int64 newPosition)=0
Tries to move the stream's output position.
virtual bool writeShortBigEndian(short value)
Writes a 16-bit integer to the stream in a big-endian byte order.
virtual bool writeInt(int value)
Writes a 32-bit integer to the stream in a little-endian byte order.
A general-purpose range object, that simply represents any linear range with a start and end point.
constexpr bool contains(const ValueType position) const noexcept
Returns true if the given position lies inside this range.
String & getReference(int index) noexcept
Returns a reference to one of the strings in the array.
A container for holding a set of strings which are keyed by another string.
String getValue(StringRef, const String &defaultReturnValue) const
Finds the value corresponding to a key string.
const StringArray & getAllValues() const noexcept
Returns a list of all values in the array.
void addMap(const std::map< String, String > &mapToAdd)
Adds the contents of a map to this StringPairArray.
int size() const noexcept
Returns the number of strings in the array.
const StringArray & getAllKeys() const noexcept
Returns a list of all keys in the array.
int getIntValue() const noexcept
Reads the value of the string as a decimal number (up to 32 bits in size).
void zerostruct(Type &structure) noexcept
Overwrites a structure or object with zeros.
unsigned short uint16
A platform-independent 16-bit unsigned integer type.
wchar_t juce_wchar
A platform-independent 32-bit unicode character type.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
constexpr Type jmax(Type a, Type b)
Returns the larger of two values.
RangedDirectoryIterator end(const RangedDirectoryIterator &)
Returns a default-constructed sentinel value.
signed short int16
A platform-independent 16-bit signed integer type.
signed char int8
A platform-independent 8-bit signed integer type.
unsigned long long uint64
A platform-independent 64-bit unsigned integer type.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
unsigned int uint32
A platform-independent 32-bit unsigned integer type.
unsigned char uint8
A platform-independent 8-bit unsigned integer type.
constexpr int numElementsInArray(Type(&)[N]) noexcept
Handy function for getting the number of elements in a simple const C array.
long long int64
A platform-independent 64-bit integer type.
void zeromem(void *memory, size_t numBytes) noexcept
Fills a block of memory with zeros.