Loading...
Searching...
No Matches
juce_WavAudioFormat.cpp
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
using StringMap = std::unordered_map<String, String>;
static auto toMap (const StringPairArray& array)
{
StringMap result;
for (auto i = 0; i < array.size(); ++i)
result[array.getAllKeys()[i]] = array.getAllValues()[i];
return result;
}
static auto getValueWithDefault (const StringMap& m, const String& key, const String& fallback = {})
{
const auto iter = m.find (key);
return iter != m.cend() ? iter->second : fallback;
}
static const char* const wavFormatName = "WAV file";
//==============================================================================
const char* const WavAudioFormat::bwavDescription = "bwav description";
const char* const WavAudioFormat::bwavOriginator = "bwav originator";
const char* const WavAudioFormat::bwavOriginatorRef = "bwav originator ref";
const char* const WavAudioFormat::bwavOriginationDate = "bwav origination date";
const char* const WavAudioFormat::bwavOriginationTime = "bwav origination time";
const char* const WavAudioFormat::bwavTimeReference = "bwav time reference";
const char* const WavAudioFormat::bwavCodingHistory = "bwav coding history";
StringPairArray WavAudioFormat::createBWAVMetadata (const String& description,
const String& originator,
const String& originatorRef,
Time date,
int64 timeReferenceSamples,
const String& codingHistory)
{
StringPairArray m;
m.set (bwavDescription, description);
m.set (bwavOriginator, originator);
m.set (bwavOriginatorRef, originatorRef);
m.set (bwavOriginationDate, date.formatted ("%Y-%m-%d"));
m.set (bwavOriginationTime, date.formatted ("%H:%M:%S"));
m.set (bwavTimeReference, String (timeReferenceSamples));
m.set (bwavCodingHistory, codingHistory);
return m;
}
const char* const WavAudioFormat::acidOneShot = "acid one shot";
const char* const WavAudioFormat::acidRootSet = "acid root set";
const char* const WavAudioFormat::acidStretch = "acid stretch";
const char* const WavAudioFormat::acidDiskBased = "acid disk based";
const char* const WavAudioFormat::acidizerFlag = "acidizer flag";
const char* const WavAudioFormat::acidRootNote = "acid root note";
const char* const WavAudioFormat::acidBeats = "acid beats";
const char* const WavAudioFormat::acidDenominator = "acid denominator";
const char* const WavAudioFormat::acidNumerator = "acid numerator";
const char* const WavAudioFormat::acidTempo = "acid tempo";
const char* const WavAudioFormat::riffInfoArchivalLocation = "IARL";
const char* const WavAudioFormat::riffInfoArtist = "IART";
const char* const WavAudioFormat::riffInfoBaseURL = "IBSU";
const char* const WavAudioFormat::riffInfoCinematographer = "ICNM";
const char* const WavAudioFormat::riffInfoComment = "CMNT";
const char* const WavAudioFormat::riffInfoComment2 = "ICMT";
const char* const WavAudioFormat::riffInfoComments = "COMM";
const char* const WavAudioFormat::riffInfoCommissioned = "ICMS";
const char* const WavAudioFormat::riffInfoCopyright = "ICOP";
const char* const WavAudioFormat::riffInfoCostumeDesigner = "ICDS";
const char* const WavAudioFormat::riffInfoCountry = "ICNT";
const char* const WavAudioFormat::riffInfoCropped = "ICRP";
const char* const WavAudioFormat::riffInfoDateCreated = "ICRD";
const char* const WavAudioFormat::riffInfoDateTimeOriginal = "IDIT";
const char* const WavAudioFormat::riffInfoDefaultAudioStream = "ICAS";
const char* const WavAudioFormat::riffInfoDimension = "IDIM";
const char* const WavAudioFormat::riffInfoDirectory = "DIRC";
const char* const WavAudioFormat::riffInfoDistributedBy = "IDST";
const char* const WavAudioFormat::riffInfoDotsPerInch = "IDPI";
const char* const WavAudioFormat::riffInfoEditedBy = "IEDT";
const char* const WavAudioFormat::riffInfoEighthLanguage = "IAS8";
const char* const WavAudioFormat::riffInfoEncodedBy = "CODE";
const char* const WavAudioFormat::riffInfoEndTimecode = "TCDO";
const char* const WavAudioFormat::riffInfoEngineer = "IENG";
const char* const WavAudioFormat::riffInfoFifthLanguage = "IAS5";
const char* const WavAudioFormat::riffInfoFirstLanguage = "IAS1";
const char* const WavAudioFormat::riffInfoFourthLanguage = "IAS4";
const char* const WavAudioFormat::riffInfoGenre = "GENR";
const char* const WavAudioFormat::riffInfoKeywords = "IKEY";
const char* const WavAudioFormat::riffInfoLanguage = "LANG";
const char* const WavAudioFormat::riffInfoLength = "TLEN";
const char* const WavAudioFormat::riffInfoLightness = "ILGT";
const char* const WavAudioFormat::riffInfoLocation = "LOCA";
const char* const WavAudioFormat::riffInfoLogoIconURL = "ILIU";
const char* const WavAudioFormat::riffInfoLogoURL = "ILGU";
const char* const WavAudioFormat::riffInfoMedium = "IMED";
const char* const WavAudioFormat::riffInfoMoreInfoBannerImage = "IMBI";
const char* const WavAudioFormat::riffInfoMoreInfoBannerURL = "IMBU";
const char* const WavAudioFormat::riffInfoMoreInfoText = "IMIT";
const char* const WavAudioFormat::riffInfoMoreInfoURL = "IMIU";
const char* const WavAudioFormat::riffInfoMusicBy = "IMUS";
const char* const WavAudioFormat::riffInfoNinthLanguage = "IAS9";
const char* const WavAudioFormat::riffInfoNumberOfParts = "PRT2";
const char* const WavAudioFormat::riffInfoOrganisation = "TORG";
const char* const WavAudioFormat::riffInfoPart = "PRT1";
const char* const WavAudioFormat::riffInfoProducedBy = "IPRO";
const char* const WavAudioFormat::riffInfoProductName = "IPRD";
const char* const WavAudioFormat::riffInfoProductionDesigner = "IPDS";
const char* const WavAudioFormat::riffInfoProductionStudio = "ISDT";
const char* const WavAudioFormat::riffInfoRate = "RATE";
const char* const WavAudioFormat::riffInfoRated = "AGES";
const char* const WavAudioFormat::riffInfoRating = "IRTD";
const char* const WavAudioFormat::riffInfoRippedBy = "IRIP";
const char* const WavAudioFormat::riffInfoSecondaryGenre = "ISGN";
const char* const WavAudioFormat::riffInfoSecondLanguage = "IAS2";
const char* const WavAudioFormat::riffInfoSeventhLanguage = "IAS7";
const char* const WavAudioFormat::riffInfoSharpness = "ISHP";
const char* const WavAudioFormat::riffInfoSixthLanguage = "IAS6";
const char* const WavAudioFormat::riffInfoSoftware = "ISFT";
const char* const WavAudioFormat::riffInfoSoundSchemeTitle = "DISP";
const char* const WavAudioFormat::riffInfoSource = "ISRC";
const char* const WavAudioFormat::riffInfoSourceFrom = "ISRF";
const char* const WavAudioFormat::riffInfoStarring_ISTR = "ISTR";
const char* const WavAudioFormat::riffInfoStarring_STAR = "STAR";
const char* const WavAudioFormat::riffInfoStartTimecode = "TCOD";
const char* const WavAudioFormat::riffInfoStatistics = "STAT";
const char* const WavAudioFormat::riffInfoSubject = "ISBJ";
const char* const WavAudioFormat::riffInfoTapeName = "TAPE";
const char* const WavAudioFormat::riffInfoTechnician = "ITCH";
const char* const WavAudioFormat::riffInfoThirdLanguage = "IAS3";
const char* const WavAudioFormat::riffInfoTimeCode = "ISMP";
const char* const WavAudioFormat::riffInfoTitle = "INAM";
const char* const WavAudioFormat::riffInfoTrackNo = "IPRT";
const char* const WavAudioFormat::riffInfoTrackNumber = "TRCK";
const char* const WavAudioFormat::riffInfoURL = "TURL";
const char* const WavAudioFormat::riffInfoVegasVersionMajor = "VMAJ";
const char* const WavAudioFormat::riffInfoVegasVersionMinor = "VMIN";
const char* const WavAudioFormat::riffInfoVersion = "TVER";
const char* const WavAudioFormat::riffInfoWatermarkURL = "IWMU";
const char* const WavAudioFormat::riffInfoWrittenBy = "IWRI";
const char* const WavAudioFormat::riffInfoYear = "YEAR";
const char* const WavAudioFormat::aswgContentType = "contentType";
const char* const WavAudioFormat::aswgProject = "project";
const char* const WavAudioFormat::aswgOriginator = "originator";
const char* const WavAudioFormat::aswgOriginatorStudio = "originatorStudio";
const char* const WavAudioFormat::aswgNotes = "notes";
const char* const WavAudioFormat::aswgSession = "session";
const char* const WavAudioFormat::aswgState = "state";
const char* const WavAudioFormat::aswgEditor = "editor";
const char* const WavAudioFormat::aswgMixer = "mixer";
const char* const WavAudioFormat::aswgFxChainName = "fxChainName";
const char* const WavAudioFormat::aswgChannelConfig = "channelConfig";
const char* const WavAudioFormat::aswgAmbisonicFormat = "ambisonicFormat";
const char* const WavAudioFormat::aswgAmbisonicChnOrder = "ambisonicChnOrder";
const char* const WavAudioFormat::aswgAmbisonicNorm = "ambisonicNorm";
const char* const WavAudioFormat::aswgMicType = "micType";
const char* const WavAudioFormat::aswgMicConfig = "micConfig";
const char* const WavAudioFormat::aswgMicDistance = "micDistance";
const char* const WavAudioFormat::aswgRecordingLoc = "recordingLoc";
const char* const WavAudioFormat::aswgIsDesigned = "isDesigned";
const char* const WavAudioFormat::aswgRecEngineer = "recEngineer";
const char* const WavAudioFormat::aswgRecStudio = "recStudio";
const char* const WavAudioFormat::aswgImpulseLocation = "impulseLocation";
const char* const WavAudioFormat::aswgCategory = "category";
const char* const WavAudioFormat::aswgSubCategory = "subCategory";
const char* const WavAudioFormat::aswgCatId = "catId";
const char* const WavAudioFormat::aswgUserCategory = "userCategory";
const char* const WavAudioFormat::aswgUserData = "userData";
const char* const WavAudioFormat::aswgVendorCategory = "vendorCategory";
const char* const WavAudioFormat::aswgFxName = "fxName";
const char* const WavAudioFormat::aswgLibrary = "library";
const char* const WavAudioFormat::aswgCreatorId = "creatorId";
const char* const WavAudioFormat::aswgSourceId = "sourceId";
const char* const WavAudioFormat::aswgRmsPower = "rmsPower";
const char* const WavAudioFormat::aswgLoudness = "loudness";
const char* const WavAudioFormat::aswgLoudnessRange = "loudnessRange";
const char* const WavAudioFormat::aswgMaxPeak = "maxPeak";
const char* const WavAudioFormat::aswgSpecDensity = "specDensity";
const char* const WavAudioFormat::aswgZeroCrossRate = "zeroCrossRate";
const char* const WavAudioFormat::aswgPapr = "papr";
const char* const WavAudioFormat::aswgText = "text";
const char* const WavAudioFormat::aswgEfforts = "efforts";
const char* const WavAudioFormat::aswgEffortType = "effortType";
const char* const WavAudioFormat::aswgProjection = "projection";
const char* const WavAudioFormat::aswgLanguage = "language";
const char* const WavAudioFormat::aswgTimingRestriction = "timingRestriction";
const char* const WavAudioFormat::aswgCharacterName = "characterName";
const char* const WavAudioFormat::aswgCharacterGender = "characterGender";
const char* const WavAudioFormat::aswgCharacterAge = "characterAge";
const char* const WavAudioFormat::aswgCharacterRole = "characterRole";
const char* const WavAudioFormat::aswgActorName = "actorName";
const char* const WavAudioFormat::aswgActorGender = "actorGender";
const char* const WavAudioFormat::aswgDirector = "director";
const char* const WavAudioFormat::aswgDirection = "direction";
const char* const WavAudioFormat::aswgFxUsed = "fxUsed";
const char* const WavAudioFormat::aswgUsageRights = "usageRights";
const char* const WavAudioFormat::aswgIsUnion = "isUnion";
const char* const WavAudioFormat::aswgAccent = "accent";
const char* const WavAudioFormat::aswgEmotion = "emotion";
const char* const WavAudioFormat::aswgComposor = "composor";
const char* const WavAudioFormat::aswgArtist = "artist";
const char* const WavAudioFormat::aswgSongTitle = "songTitle";
const char* const WavAudioFormat::aswgGenre = "genre";
const char* const WavAudioFormat::aswgSubGenre = "subGenre";
const char* const WavAudioFormat::aswgProducer = "producer";
const char* const WavAudioFormat::aswgMusicSup = "musicSup";
const char* const WavAudioFormat::aswgInstrument = "instrument";
const char* const WavAudioFormat::aswgMusicPublisher = "musicPublisher";
const char* const WavAudioFormat::aswgRightsOwner = "rightsOwner";
const char* const WavAudioFormat::aswgIsSource = "isSource";
const char* const WavAudioFormat::aswgIsLoop = "isLoop";
const char* const WavAudioFormat::aswgIntensity = "intensity";
const char* const WavAudioFormat::aswgIsFinal = "isFinal";
const char* const WavAudioFormat::aswgOrderRef = "orderRef";
const char* const WavAudioFormat::aswgIsOst = "isOst";
const char* const WavAudioFormat::aswgIsCinematic = "isCinematic";
const char* const WavAudioFormat::aswgIsLicensed = "isLicensed";
const char* const WavAudioFormat::aswgIsDiegetic = "isDiegetic";
const char* const WavAudioFormat::aswgMusicVersion = "musicVersion";
const char* const WavAudioFormat::aswgIsrcId = "isrcId";
const char* const WavAudioFormat::aswgTempo = "tempo";
const char* const WavAudioFormat::aswgTimeSig = "timeSig";
const char* const WavAudioFormat::aswgInKey = "inKey";
const char* const WavAudioFormat::aswgBillingCode = "billingCode";
const char* const WavAudioFormat::aswgVersion = "IXML_VERSION";
const char* const WavAudioFormat::ISRC = "ISRC";
const char* const WavAudioFormat::internationalStandardRecordingCode = "international standard recording code";
const char* const WavAudioFormat::tracktionLoopInfo = "tracktion loop info";
//==============================================================================
namespace WavFileHelpers
{
constexpr inline int chunkName (const char* name) noexcept { return (int) ByteOrder::littleEndianInt (name); }
constexpr inline size_t roundUpSize (size_t sz) noexcept { return (sz + 3) & ~3u; }
#if JUCE_MSVC
#pragma pack (push, 1)
#endif
struct BWAVChunk
{
char description[256];
char originator[32];
char originatorRef[32];
char originationDate[10];
char originationTime[8];
uint32 timeRefLow;
uint32 timeRefHigh;
uint16 version;
uint8 umid[64];
uint8 reserved[190];
char codingHistory[1];
void copyTo (StringMap& values, const int totalSize) const
{
values[WavAudioFormat::bwavDescription] = String::fromUTF8 (description, sizeof (description));
values[WavAudioFormat::bwavOriginator] = String::fromUTF8 (originator, sizeof (originator));
values[WavAudioFormat::bwavOriginatorRef] = String::fromUTF8 (originatorRef, sizeof (originatorRef));
values[WavAudioFormat::bwavOriginationDate] = String::fromUTF8 (originationDate, sizeof (originationDate));
values[WavAudioFormat::bwavOriginationTime] = String::fromUTF8 (originationTime, sizeof (originationTime));
auto timeLow = ByteOrder::swapIfBigEndian (timeRefLow);
auto timeHigh = ByteOrder::swapIfBigEndian (timeRefHigh);
auto time = (((int64) timeHigh) << 32) + timeLow;
values[WavAudioFormat::bwavTimeReference] = String (time);
values[WavAudioFormat::bwavCodingHistory] = String::fromUTF8 (codingHistory, totalSize - (int) offsetof (BWAVChunk, codingHistory));
}
static MemoryBlock createFrom (const StringMap& values)
{
MemoryBlock data (roundUpSize (sizeof (BWAVChunk) + getValueWithDefault (values, WavAudioFormat::bwavCodingHistory).getNumBytesAsUTF8()));
data.fillWith (0);
auto* b = (BWAVChunk*) data.getData();
// Allow these calls to overwrite an extra byte at the end, which is fine as long
// as they get called in the right order.
getValueWithDefault (values, WavAudioFormat::bwavDescription) .copyToUTF8 (b->description, 257);
getValueWithDefault (values, WavAudioFormat::bwavOriginator) .copyToUTF8 (b->originator, 33);
getValueWithDefault (values, WavAudioFormat::bwavOriginatorRef) .copyToUTF8 (b->originatorRef, 33);
getValueWithDefault (values, WavAudioFormat::bwavOriginationDate).copyToUTF8 (b->originationDate, 11);
getValueWithDefault (values, WavAudioFormat::bwavOriginationTime).copyToUTF8 (b->originationTime, 9);
auto time = getValueWithDefault (values, WavAudioFormat::bwavTimeReference).getLargeIntValue();
b->timeRefLow = ByteOrder::swapIfBigEndian ((uint32) (time & 0xffffffff));
b->timeRefHigh = ByteOrder::swapIfBigEndian ((uint32) (time >> 32));
getValueWithDefault (values, WavAudioFormat::bwavCodingHistory).copyToUTF8 (b->codingHistory, 0x7fffffff);
if (b->description[0] != 0
|| b->originator[0] != 0
|| b->originationDate[0] != 0
|| b->originationTime[0] != 0
|| b->codingHistory[0] != 0
|| time != 0)
{
return data;
}
return {};
}
} JUCE_PACKED;
//==============================================================================
inline AudioChannelSet canonicalWavChannelSet (int numChannels)
{
if (numChannels == 1) return AudioChannelSet::mono();
if (numChannels == 2) return AudioChannelSet::stereo();
if (numChannels == 3) return AudioChannelSet::createLCR();
if (numChannels == 4) return AudioChannelSet::quadraphonic();
if (numChannels == 5) return AudioChannelSet::create5point0();
if (numChannels == 6) return AudioChannelSet::create5point1();
if (numChannels == 7) return AudioChannelSet::create7point0SDDS();
if (numChannels == 8) return AudioChannelSet::create7point1SDDS();
return AudioChannelSet::discreteChannels (numChannels);
}
//==============================================================================
struct SMPLChunk
{
struct SampleLoop
{
uint32 identifier;
uint32 type; // these are different in AIFF and WAV
uint32 start;
uint32 end;
uint32 fraction;
uint32 playCount;
} JUCE_PACKED;
uint32 manufacturer;
uint32 product;
uint32 samplePeriod;
uint32 midiUnityNote;
uint32 midiPitchFraction;
uint32 smpteFormat;
uint32 smpteOffset;
uint32 numSampleLoops;
uint32 samplerData;
SampleLoop loops[1];
template <typename NameType>
static void setValue (StringMap& values, NameType name, uint32 val)
{
values[name] = String (ByteOrder::swapIfBigEndian (val));
}
static void setValue (StringMap& values, int prefix, const char* name, uint32 val)
{
setValue (values, "Loop" + String (prefix) + name, val);
}
void copyTo (StringMap& values, const int totalSize) const
{
setValue (values, "Manufacturer", manufacturer);
setValue (values, "Product", product);
setValue (values, "SamplePeriod", samplePeriod);
setValue (values, "MidiUnityNote", midiUnityNote);
setValue (values, "MidiPitchFraction", midiPitchFraction);
setValue (values, "SmpteFormat", smpteFormat);
setValue (values, "SmpteOffset", smpteOffset);
setValue (values, "NumSampleLoops", numSampleLoops);
setValue (values, "SamplerData", samplerData);
for (int i = 0; i < (int) numSampleLoops; ++i)
{
if ((uint8*) (loops + (i + 1)) > ((uint8*) this) + totalSize)
break;
setValue (values, i, "Identifier", loops[i].identifier);
setValue (values, i, "Type", loops[i].type);
setValue (values, i, "Start", loops[i].start);
setValue (values, i, "End", loops[i].end);
setValue (values, i, "Fraction", loops[i].fraction);
setValue (values, i, "PlayCount", loops[i].playCount);
}
}
template <typename NameType>
static uint32 getValue (const StringMap& values, NameType name, const char* def)
{
return ByteOrder::swapIfBigEndian ((uint32) getValueWithDefault (values, name, def).getIntValue());
}
static uint32 getValue (const StringMap& values, int prefix, const char* name, const char* def)
{
return getValue (values, "Loop" + String (prefix) + name, def);
}
static MemoryBlock createFrom (const StringMap& values)
{
MemoryBlock data;
auto numLoops = jmin (64, getValueWithDefault (values, "NumSampleLoops", "0").getIntValue());
data.setSize (roundUpSize (sizeof (SMPLChunk) + (size_t) (jmax (0, numLoops - 1)) * sizeof (SampleLoop)), true);
auto s = static_cast<SMPLChunk*> (data.getData());
s->manufacturer = getValue (values, "Manufacturer", "0");
s->product = getValue (values, "Product", "0");
s->samplePeriod = getValue (values, "SamplePeriod", "0");
s->midiUnityNote = getValue (values, "MidiUnityNote", "60");
s->midiPitchFraction = getValue (values, "MidiPitchFraction", "0");
s->smpteFormat = getValue (values, "SmpteFormat", "0");
s->smpteOffset = getValue (values, "SmpteOffset", "0");
s->numSampleLoops = ByteOrder::swapIfBigEndian ((uint32) numLoops);
s->samplerData = getValue (values, "SamplerData", "0");
for (int i = 0; i < numLoops; ++i)
{
auto& loop = s->loops[i];
loop.identifier = getValue (values, i, "Identifier", "0");
loop.type = getValue (values, i, "Type", "0");
loop.start = getValue (values, i, "Start", "0");
loop.end = getValue (values, i, "End", "0");
loop.fraction = getValue (values, i, "Fraction", "0");
loop.playCount = getValue (values, i, "PlayCount", "0");
}
return data;
}
} JUCE_PACKED;
//==============================================================================
struct InstChunk
{
int8 baseNote;
int8 detune;
int8 gain;
int8 lowNote;
int8 highNote;
int8 lowVelocity;
int8 highVelocity;
static void setValue (StringMap& values, const char* name, int val)
{
values[name] = String (val);
}
void copyTo (StringMap& values) const
{
setValue (values, "MidiUnityNote", baseNote);
setValue (values, "Detune", detune);
setValue (values, "Gain", gain);
setValue (values, "LowNote", lowNote);
setValue (values, "HighNote", highNote);
setValue (values, "LowVelocity", lowVelocity);
setValue (values, "HighVelocity", highVelocity);
}
static int8 getValue (const StringMap& values, const char* name, const char* def)
{
return (int8) getValueWithDefault (values, name, def).getIntValue();
}
static MemoryBlock createFrom (const StringMap& values)
{
MemoryBlock data;
if ( values.find ("LowNote") != values.cend()
&& values.find ("HighNote") != values.cend())
{
data.setSize (8, true);
auto* inst = static_cast<InstChunk*> (data.getData());
inst->baseNote = getValue (values, "MidiUnityNote", "60");
inst->detune = getValue (values, "Detune", "0");
inst->gain = getValue (values, "Gain", "0");
inst->lowNote = getValue (values, "LowNote", "0");
inst->highNote = getValue (values, "HighNote", "127");
inst->lowVelocity = getValue (values, "LowVelocity", "1");
inst->highVelocity = getValue (values, "HighVelocity", "127");
}
return data;
}
} JUCE_PACKED;
//==============================================================================
struct CueChunk
{
struct Cue
{
uint32 identifier;
uint32 order;
uint32 chunkID;
uint32 chunkStart;
uint32 blockStart;
uint32 offset;
} JUCE_PACKED;
uint32 numCues;
Cue cues[1];
static void setValue (StringMap& values, int prefix, const char* name, uint32 val)
{
values["Cue" + String (prefix) + name] = String (ByteOrder::swapIfBigEndian (val));
}
void copyTo (StringMap& values, const int totalSize) const
{
values["NumCuePoints"] = String (ByteOrder::swapIfBigEndian (numCues));
for (int i = 0; i < (int) numCues; ++i)
{
if ((uint8*) (cues + (i + 1)) > ((uint8*) this) + totalSize)
break;
setValue (values, i, "Identifier", cues[i].identifier);
setValue (values, i, "Order", cues[i].order);
setValue (values, i, "ChunkID", cues[i].chunkID);
setValue (values, i, "ChunkStart", cues[i].chunkStart);
setValue (values, i, "BlockStart", cues[i].blockStart);
setValue (values, i, "Offset", cues[i].offset);
}
}
static MemoryBlock createFrom (const StringMap& values)
{
MemoryBlock data;
const int numCues = getValueWithDefault (values, "NumCuePoints", "0").getIntValue();
if (numCues > 0)
{
data.setSize (roundUpSize (sizeof (CueChunk) + (size_t) (numCues - 1) * sizeof (Cue)), true);
auto c = static_cast<CueChunk*> (data.getData());
c->numCues = ByteOrder::swapIfBigEndian ((uint32) numCues);
const String dataChunkID (chunkName ("data"));
int nextOrder = 0;
#if JUCE_DEBUG
Array<uint32> identifiers;
#endif
for (int i = 0; i < numCues; ++i)
{
auto prefix = "Cue" + String (i);
auto identifier = (uint32) getValueWithDefault (values, prefix + "Identifier", "0").getIntValue();
#if JUCE_DEBUG
jassert (! identifiers.contains (identifier));
identifiers.add (identifier);
#endif
auto order = getValueWithDefault (values, prefix + "Order", String (nextOrder)).getIntValue();
nextOrder = jmax (nextOrder, order) + 1;
auto& cue = c->cues[i];
cue.identifier = ByteOrder::swapIfBigEndian ((uint32) identifier);
cue.order = ByteOrder::swapIfBigEndian ((uint32) order);
cue.chunkID = ByteOrder::swapIfBigEndian ((uint32) getValueWithDefault (values, prefix + "ChunkID", dataChunkID).getIntValue());
cue.chunkStart = ByteOrder::swapIfBigEndian ((uint32) getValueWithDefault (values, prefix + "ChunkStart", "0").getIntValue());
cue.blockStart = ByteOrder::swapIfBigEndian ((uint32) getValueWithDefault (values, prefix + "BlockStart", "0").getIntValue());
cue.offset = ByteOrder::swapIfBigEndian ((uint32) getValueWithDefault (values, prefix + "Offset", "0").getIntValue());
}
}
return data;
}
} JUCE_PACKED;
//==============================================================================
namespace ListChunk
{
static int getValue (const StringMap& values, const String& name)
{
return getValueWithDefault (values, name, "0").getIntValue();
}
static int getValue (const StringMap& values, const String& prefix, const char* name)
{
return getValue (values, prefix + name);
}
static void appendLabelOrNoteChunk (const StringMap& values, const String& prefix,
const int chunkType, MemoryOutputStream& out)
{
auto label = getValueWithDefault (values, prefix + "Text", prefix);
auto labelLength = (int) label.getNumBytesAsUTF8() + 1;
auto chunkLength = 4 + labelLength + (labelLength & 1);
out.writeInt (chunkType);
out.writeInt (chunkLength);
out.writeInt (getValue (values, prefix, "Identifier"));
out.write (label.toUTF8(), (size_t) labelLength);
if ((out.getDataSize() & 1) != 0)
out.writeByte (0);
}
static void appendExtraChunk (const StringMap& values, const String& prefix, MemoryOutputStream& out)
{
auto text = getValueWithDefault (values, prefix + "Text", prefix);
auto textLength = (int) text.getNumBytesAsUTF8() + 1; // include null terminator
auto chunkLength = textLength + 20 + (textLength & 1);
out.writeInt (chunkName ("ltxt"));
out.writeInt (chunkLength);
out.writeInt (getValue (values, prefix, "Identifier"));
out.writeInt (getValue (values, prefix, "SampleLength"));
out.writeInt (getValue (values, prefix, "Purpose"));
out.writeShort ((short) getValue (values, prefix, "Country"));
out.writeShort ((short) getValue (values, prefix, "Language"));
out.writeShort ((short) getValue (values, prefix, "Dialect"));
out.writeShort ((short) getValue (values, prefix, "CodePage"));
out.write (text.toUTF8(), (size_t) textLength);
if ((out.getDataSize() & 1) != 0)
out.writeByte (0);
}
static MemoryBlock createFrom (const StringMap& values)
{
auto numCueLabels = getValue (values, "NumCueLabels");
auto numCueNotes = getValue (values, "NumCueNotes");
auto numCueRegions = getValue (values, "NumCueRegions");
MemoryOutputStream out;
if (numCueLabels + numCueNotes + numCueRegions > 0)
{
out.writeInt (chunkName ("adtl"));
for (int i = 0; i < numCueLabels; ++i)
appendLabelOrNoteChunk (values, "CueLabel" + String (i), chunkName ("labl"), out);
for (int i = 0; i < numCueNotes; ++i)
appendLabelOrNoteChunk (values, "CueNote" + String (i), chunkName ("note"), out);
for (int i = 0; i < numCueRegions; ++i)
appendExtraChunk (values, "CueRegion" + String (i), out);
}
return out.getMemoryBlock();
}
}
//==============================================================================
namespace ListInfoChunk
{
static const char* const types[] =
{
WavAudioFormat::riffInfoArchivalLocation,
WavAudioFormat::riffInfoArtist,
WavAudioFormat::riffInfoBaseURL,
WavAudioFormat::riffInfoCinematographer,
WavAudioFormat::riffInfoComment,
WavAudioFormat::riffInfoComments,
WavAudioFormat::riffInfoComment2,
WavAudioFormat::riffInfoCommissioned,
WavAudioFormat::riffInfoCopyright,
WavAudioFormat::riffInfoCostumeDesigner,
WavAudioFormat::riffInfoCountry,
WavAudioFormat::riffInfoCropped,
WavAudioFormat::riffInfoDateCreated,
WavAudioFormat::riffInfoDateTimeOriginal,
WavAudioFormat::riffInfoDefaultAudioStream,
WavAudioFormat::riffInfoDimension,
WavAudioFormat::riffInfoDirectory,
WavAudioFormat::riffInfoDistributedBy,
WavAudioFormat::riffInfoDotsPerInch,
WavAudioFormat::riffInfoEditedBy,
WavAudioFormat::riffInfoEighthLanguage,
WavAudioFormat::riffInfoEncodedBy,
WavAudioFormat::riffInfoEndTimecode,
WavAudioFormat::riffInfoEngineer,
WavAudioFormat::riffInfoFifthLanguage,
WavAudioFormat::riffInfoFirstLanguage,
WavAudioFormat::riffInfoFourthLanguage,
WavAudioFormat::riffInfoGenre,
WavAudioFormat::riffInfoKeywords,
WavAudioFormat::riffInfoLanguage,
WavAudioFormat::riffInfoLength,
WavAudioFormat::riffInfoLightness,
WavAudioFormat::riffInfoLocation,
WavAudioFormat::riffInfoLogoIconURL,
WavAudioFormat::riffInfoLogoURL,
WavAudioFormat::riffInfoMedium,
WavAudioFormat::riffInfoMoreInfoBannerImage,
WavAudioFormat::riffInfoMoreInfoBannerURL,
WavAudioFormat::riffInfoMoreInfoText,
WavAudioFormat::riffInfoMoreInfoURL,
WavAudioFormat::riffInfoMusicBy,
WavAudioFormat::riffInfoNinthLanguage,
WavAudioFormat::riffInfoNumberOfParts,
WavAudioFormat::riffInfoOrganisation,
WavAudioFormat::riffInfoPart,
WavAudioFormat::riffInfoProducedBy,
WavAudioFormat::riffInfoProductName,
WavAudioFormat::riffInfoProductionDesigner,
WavAudioFormat::riffInfoProductionStudio,
WavAudioFormat::riffInfoRate,
WavAudioFormat::riffInfoRated,
WavAudioFormat::riffInfoRating,
WavAudioFormat::riffInfoRippedBy,
WavAudioFormat::riffInfoSecondaryGenre,
WavAudioFormat::riffInfoSecondLanguage,
WavAudioFormat::riffInfoSeventhLanguage,
WavAudioFormat::riffInfoSharpness,
WavAudioFormat::riffInfoSixthLanguage,
WavAudioFormat::riffInfoSoftware,
WavAudioFormat::riffInfoSoundSchemeTitle,
WavAudioFormat::riffInfoSource,
WavAudioFormat::riffInfoSourceFrom,
WavAudioFormat::riffInfoStarring_ISTR,
WavAudioFormat::riffInfoStarring_STAR,
WavAudioFormat::riffInfoStartTimecode,
WavAudioFormat::riffInfoStatistics,
WavAudioFormat::riffInfoSubject,
WavAudioFormat::riffInfoTapeName,
WavAudioFormat::riffInfoTechnician,
WavAudioFormat::riffInfoThirdLanguage,
WavAudioFormat::riffInfoTimeCode,
WavAudioFormat::riffInfoTitle,
WavAudioFormat::riffInfoTrackNo,
WavAudioFormat::riffInfoTrackNumber,
WavAudioFormat::riffInfoURL,
WavAudioFormat::riffInfoVegasVersionMajor,
WavAudioFormat::riffInfoVegasVersionMinor,
WavAudioFormat::riffInfoVersion,
WavAudioFormat::riffInfoWatermarkURL,
WavAudioFormat::riffInfoWrittenBy,
WavAudioFormat::riffInfoYear
};
static bool isMatchingTypeIgnoringCase (const int value, const char* const name) noexcept
{
for (int i = 0; i < 4; ++i)
if ((juce_wchar) name[i] != CharacterFunctions::toUpperCase ((juce_wchar) ((value >> (i * 8)) & 0xff)))
return false;
return true;
}
static void addToMetadata (StringMap& values, InputStream& input, int64 chunkEnd)
{
while (input.getPosition() < chunkEnd)
{
auto infoType = input.readInt();
auto infoLength = chunkEnd - input.getPosition();
if (infoLength > 0)
{
infoLength = jmin (infoLength, (int64) input.readInt());
if (infoLength <= 0)
return;
for (auto& type : types)
{
if (isMatchingTypeIgnoringCase (infoType, type))
{
MemoryBlock mb;
input.readIntoMemoryBlock (mb, (ssize_t) infoLength);
values[type] = String::createStringFromData ((const char*) mb.getData(),
(int) mb.getSize());
break;
}
}
}
}
}
static bool writeValue (const StringMap& values, MemoryOutputStream& out, const char* paramName)
{
auto value = getValueWithDefault (values, paramName, {});
if (value.isEmpty())
return false;
auto valueLength = (int) value.getNumBytesAsUTF8() + 1;
auto chunkLength = valueLength + (valueLength & 1);
out.writeInt (chunkName (paramName));
out.writeInt (chunkLength);
out.write (value.toUTF8(), (size_t) valueLength);
if ((out.getDataSize() & 1) != 0)
out.writeByte (0);
return true;
}
static MemoryBlock createFrom (const StringMap& values)
{
MemoryOutputStream out;
out.writeInt (chunkName ("INFO"));
bool anyParamsDefined = false;
for (auto& type : types)
if (writeValue (values, out, type))
anyParamsDefined = true;
return anyParamsDefined ? out.getMemoryBlock() : MemoryBlock();
}
}
//==============================================================================
struct AcidChunk
{
AcidChunk (InputStream& input, size_t length)
{
zerostruct (*this);
input.read (this, (int) jmin (sizeof (*this), length));
}
AcidChunk (const StringMap& values)
{
zerostruct (*this);
flags = getFlagIfPresent (values, WavAudioFormat::acidOneShot, 0x01)
| getFlagIfPresent (values, WavAudioFormat::acidRootSet, 0x02)
| getFlagIfPresent (values, WavAudioFormat::acidStretch, 0x04)
| getFlagIfPresent (values, WavAudioFormat::acidDiskBased, 0x08)
| getFlagIfPresent (values, WavAudioFormat::acidizerFlag, 0x10);
if (getValueWithDefault (values, WavAudioFormat::acidRootSet).getIntValue() != 0)
rootNote = ByteOrder::swapIfBigEndian ((uint16) getValueWithDefault (values, WavAudioFormat::acidRootNote).getIntValue());
numBeats = ByteOrder::swapIfBigEndian ((uint32) getValueWithDefault (values, WavAudioFormat::acidBeats).getIntValue());
meterDenominator = ByteOrder::swapIfBigEndian ((uint16) getValueWithDefault (values, WavAudioFormat::acidDenominator).getIntValue());
meterNumerator = ByteOrder::swapIfBigEndian ((uint16) getValueWithDefault (values, WavAudioFormat::acidNumerator).getIntValue());
const auto iter = values.find (WavAudioFormat::acidTempo);
if (iter != values.cend())
tempo = swapFloatByteOrder (iter->second.getFloatValue());
}
static MemoryBlock createFrom (const StringMap& values)
{
return AcidChunk (values).toMemoryBlock();
}
MemoryBlock toMemoryBlock() const
{
return (flags != 0 || rootNote != 0 || numBeats != 0 || meterDenominator != 0 || meterNumerator != 0)
? MemoryBlock (this, sizeof (*this)) : MemoryBlock();
}
void addToMetadata (StringMap& values) const
{
setBoolFlag (values, WavAudioFormat::acidOneShot, 0x01);
setBoolFlag (values, WavAudioFormat::acidRootSet, 0x02);
setBoolFlag (values, WavAudioFormat::acidStretch, 0x04);
setBoolFlag (values, WavAudioFormat::acidDiskBased, 0x08);
setBoolFlag (values, WavAudioFormat::acidizerFlag, 0x10);
if (flags & 0x02) // root note set
values[WavAudioFormat::acidRootNote] = String (ByteOrder::swapIfBigEndian (rootNote));
values[WavAudioFormat::acidBeats] = String (ByteOrder::swapIfBigEndian (numBeats));
values[WavAudioFormat::acidDenominator] = String (ByteOrder::swapIfBigEndian (meterDenominator));
values[WavAudioFormat::acidNumerator] = String (ByteOrder::swapIfBigEndian (meterNumerator));
values[WavAudioFormat::acidTempo] = String (swapFloatByteOrder (tempo));
}
void setBoolFlag (StringMap& values, const char* name, uint32 mask) const
{
values[name] = (flags & ByteOrder::swapIfBigEndian (mask)) ? "1" : "0";
}
static uint32 getFlagIfPresent (const StringMap& values, const char* name, uint32 flag)
{
return getValueWithDefault (values, name).getIntValue() != 0 ? ByteOrder::swapIfBigEndian (flag) : 0;
}
static float swapFloatByteOrder (const float x) noexcept
{
#ifdef JUCE_BIG_ENDIAN
union { uint32 asInt; float asFloat; } n;
n.asFloat = x;
n.asInt = ByteOrder::swap (n.asInt);
return n.asFloat;
#else
return x;
#endif
}
uint32 flags;
uint16 rootNote;
uint16 reserved1;
float reserved2;
uint32 numBeats;
uint16 meterDenominator;
uint16 meterNumerator;
float tempo;
} JUCE_PACKED;
//==============================================================================
struct TracktionChunk
{
static MemoryBlock createFrom (const StringMap& values)
{
MemoryOutputStream out;
auto s = getValueWithDefault (values, WavAudioFormat::tracktionLoopInfo);
if (s.isNotEmpty())
{
out.writeString (s);
if ((out.getDataSize() & 1) != 0)
out.writeByte (0);
}
return out.getMemoryBlock();
}
};
//==============================================================================
namespace IXMLChunk
{
static const std::unordered_set<String> aswgMetadataKeys
{
WavAudioFormat::aswgContentType,
WavAudioFormat::aswgProject,
WavAudioFormat::aswgOriginator,
WavAudioFormat::aswgOriginatorStudio,
WavAudioFormat::aswgNotes,
WavAudioFormat::aswgSession,
WavAudioFormat::aswgState,
WavAudioFormat::aswgEditor,
WavAudioFormat::aswgMixer,
WavAudioFormat::aswgFxChainName,
WavAudioFormat::aswgChannelConfig,
WavAudioFormat::aswgAmbisonicFormat,
WavAudioFormat::aswgAmbisonicChnOrder,
WavAudioFormat::aswgAmbisonicNorm,
WavAudioFormat::aswgMicType,
WavAudioFormat::aswgMicConfig,
WavAudioFormat::aswgMicDistance,
WavAudioFormat::aswgRecordingLoc,
WavAudioFormat::aswgIsDesigned,
WavAudioFormat::aswgRecEngineer,
WavAudioFormat::aswgRecStudio,
WavAudioFormat::aswgImpulseLocation,
WavAudioFormat::aswgCategory,
WavAudioFormat::aswgSubCategory,
WavAudioFormat::aswgCatId,
WavAudioFormat::aswgUserCategory,
WavAudioFormat::aswgUserData,
WavAudioFormat::aswgVendorCategory,
WavAudioFormat::aswgFxName,
WavAudioFormat::aswgLibrary,
WavAudioFormat::aswgCreatorId,
WavAudioFormat::aswgSourceId,
WavAudioFormat::aswgRmsPower,
WavAudioFormat::aswgLoudness,
WavAudioFormat::aswgLoudnessRange,
WavAudioFormat::aswgMaxPeak,
WavAudioFormat::aswgSpecDensity,
WavAudioFormat::aswgZeroCrossRate,
WavAudioFormat::aswgPapr,
WavAudioFormat::aswgText,
WavAudioFormat::aswgEfforts,
WavAudioFormat::aswgEffortType,
WavAudioFormat::aswgProjection,
WavAudioFormat::aswgLanguage,
WavAudioFormat::aswgTimingRestriction,
WavAudioFormat::aswgCharacterName,
WavAudioFormat::aswgCharacterGender,
WavAudioFormat::aswgCharacterAge,
WavAudioFormat::aswgCharacterRole,
WavAudioFormat::aswgActorName,
WavAudioFormat::aswgActorGender,
WavAudioFormat::aswgDirector,
WavAudioFormat::aswgDirection,
WavAudioFormat::aswgFxUsed,
WavAudioFormat::aswgUsageRights,
WavAudioFormat::aswgIsUnion,
WavAudioFormat::aswgAccent,
WavAudioFormat::aswgEmotion,
WavAudioFormat::aswgComposor,
WavAudioFormat::aswgArtist,
WavAudioFormat::aswgSongTitle,
WavAudioFormat::aswgGenre,
WavAudioFormat::aswgSubGenre,
WavAudioFormat::aswgProducer,
WavAudioFormat::aswgMusicSup,
WavAudioFormat::aswgInstrument,
WavAudioFormat::aswgMusicPublisher,
WavAudioFormat::aswgRightsOwner,
WavAudioFormat::aswgIsSource,
WavAudioFormat::aswgIsLoop,
WavAudioFormat::aswgIntensity,
WavAudioFormat::aswgIsFinal,
WavAudioFormat::aswgOrderRef,
WavAudioFormat::aswgIsOst,
WavAudioFormat::aswgIsCinematic,
WavAudioFormat::aswgIsLicensed,
WavAudioFormat::aswgIsDiegetic,
WavAudioFormat::aswgMusicVersion,
WavAudioFormat::aswgIsrcId,
WavAudioFormat::aswgTempo,
WavAudioFormat::aswgTimeSig,
WavAudioFormat::aswgInKey,
WavAudioFormat::aswgBillingCode
};
static void addToMetadata (StringMap& destValues, const String& source)
{
if (auto xml = parseXML (source))
{
if (xml->hasTagName ("BWFXML"))
{
if (const auto* entry = xml->getChildByName (WavAudioFormat::aswgVersion))
destValues[WavAudioFormat::aswgVersion] = entry->getAllSubText();
if (const auto* aswgElement = xml->getChildByName ("ASWG"))
{
for (const auto* entry : aswgElement->getChildIterator())
{
const auto& tag = entry->getTagName();
if (aswgMetadataKeys.find (tag) != aswgMetadataKeys.end())
destValues[tag] = entry->getAllSubText();
}
}
}
}
}
static MemoryBlock createFrom (const StringMap& values)
{
auto createTextElement = [] (const StringRef& key, const StringRef& value)
{
auto* elem = new XmlElement (key);
elem->addTextElement (value);
return elem;
};
std::unique_ptr<XmlElement> aswgElement;
for (const auto& pair : values)
{
if (aswgMetadataKeys.find (pair.first) != aswgMetadataKeys.end())
{
if (aswgElement == nullptr)
aswgElement = std::make_unique<XmlElement> ("ASWG");
aswgElement->addChildElement (createTextElement (pair.first, pair.second));
}
}
MemoryOutputStream outputStream;
if (aswgElement != nullptr)
{
XmlElement xml ("BWFXML");
auto aswgVersion = getValueWithDefault (values, WavAudioFormat::aswgVersion, "3.01");
xml.addChildElement (createTextElement (WavAudioFormat::aswgVersion, aswgVersion));
xml.addChildElement (aswgElement.release());
xml.writeTo (outputStream);
outputStream.writeRepeatedByte (0, outputStream.getDataSize());
}
return outputStream.getMemoryBlock();
}
}
//==============================================================================
namespace AXMLChunk
{
static void addToMetadata (StringMap& destValues, const String& source)
{
if (auto xml = parseXML (source))
{
if (xml->hasTagName ("ebucore:ebuCoreMain"))
{
if (auto xml2 = xml->getChildByName ("ebucore:coreMetadata"))
{
if (auto xml3 = xml2->getChildByName ("ebucore:identifier"))
{
if (auto xml4 = xml3->getChildByName ("dc:identifier"))
{
auto ISRCCode = xml4->getAllSubText().fromFirstOccurrenceOf ("ISRC:", false, true);
if (ISRCCode.isNotEmpty())
{
// We set ISRC here for backwards compatibility.
// If the INFO 'source' field is set in the info chunk, then the
// value for this key will be overwritten later.
destValues[WavAudioFormat::riffInfoSource] = destValues[WavAudioFormat::internationalStandardRecordingCode] = ISRCCode;
}
}
}
}
}
}
}
static MemoryBlock createFrom (const StringMap& values)
{
// Use the new ISRC key if it is present, but fall back to the
// INFO 'source' value for backwards compatibility.
auto ISRC = getValueWithDefault (values,
WavAudioFormat::internationalStandardRecordingCode,
getValueWithDefault (values, WavAudioFormat::riffInfoSource));
MemoryOutputStream xml;
if (ISRC.isNotEmpty())
{
// If you are trying to set the ISRC, make sure that you are using
// WavAudioFormat::internationalStandardRecordingCode as the metadata key,
// and that the value is 12 characters long. If you are trying to set the
// 'source' field in the INFO chunk, set the
// WavAudioFormat::internationalStandardRecordingCode metadata field to the
// empty string to silence this assertion.
jassert (ISRC.length() == 12);
xml << "<ebucore:ebuCoreMain xmlns:dc=\" http://purl.org/dc/elements/1.1/\" "
"xmlns:ebucore=\"urn:ebu:metadata-schema:ebuCore_2012\">"
"<ebucore:coreMetadata>"
"<ebucore:identifier typeLabel=\"GUID\" "
"typeDefinition=\"Globally Unique Identifier\" "
"formatLabel=\"ISRC\" "
"formatDefinition=\"International Standard Recording Code\" "
"formatLink=\"http://www.ebu.ch/metadata/cs/ebu_IdentifierTypeCodeCS.xml#3.7\">"
"<dc:identifier>ISRC:" << ISRC << "</dc:identifier>"
"</ebucore:identifier>"
"</ebucore:coreMetadata>"
"</ebucore:ebuCoreMain>";
xml.writeRepeatedByte (0, xml.getDataSize()); // ensures even size, null termination and room for future growing
}
return xml.getMemoryBlock();
}
}
//==============================================================================
struct ExtensibleWavSubFormat
{
uint32 data1;
uint16 data2;
uint16 data3;
uint8 data4[8];
bool operator== (const ExtensibleWavSubFormat& other) const noexcept { return memcmp (this, &other, sizeof (*this)) == 0; }
bool operator!= (const ExtensibleWavSubFormat& other) const noexcept { return ! operator== (other); }
} JUCE_PACKED;
static const ExtensibleWavSubFormat pcmFormat = { 0x00000001, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
static const ExtensibleWavSubFormat IEEEFloatFormat = { 0x00000003, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
static const ExtensibleWavSubFormat ambisonicFormat = { 0x00000001, 0x0721, 0x11d3, { 0x86, 0x44, 0xC8, 0xC1, 0xCA, 0x00, 0x00, 0x00 } };
struct DataSize64Chunk // chunk ID = 'ds64' if data size > 0xffffffff, 'JUNK' otherwise
{
uint32 riffSizeLow; // low 4 byte size of RF64 block
uint32 riffSizeHigh; // high 4 byte size of RF64 block
uint32 dataSizeLow; // low 4 byte size of data chunk
uint32 dataSizeHigh; // high 4 byte size of data chunk
uint32 sampleCountLow; // low 4 byte sample count of fact chunk
uint32 sampleCountHigh; // high 4 byte sample count of fact chunk
uint32 tableLength; // number of valid entries in array 'table'
} JUCE_PACKED;
#if JUCE_MSVC
#pragma pack (pop)
#endif
}
//==============================================================================
class WavAudioFormatReader final : public AudioFormatReader
{
public:
WavAudioFormatReader (InputStream* in) : AudioFormatReader (in, wavFormatName)
{
using namespace WavFileHelpers;
uint64 len = 0, end = 0;
int cueNoteIndex = 0;
int cueLabelIndex = 0;
int cueRegionIndex = 0;
StringMap dict;
auto streamStartPos = input->getPosition();
auto firstChunkType = input->readInt();
if (firstChunkType == chunkName ("RF64"))
{
input->skipNextBytes (4); // size is -1 for RF64
isRF64 = true;
}
else if (firstChunkType == chunkName ("RIFF"))
{
len = (uint64) (uint32) input->readInt();
end = len + (uint64) input->getPosition();
}
else
{
return;
}
auto startOfRIFFChunk = input->getPosition();
if (input->readInt() == chunkName ("WAVE"))
{
if (isRF64 && input->readInt() == chunkName ("ds64"))
{
auto length = (uint32) input->readInt();
if (length < 28)
return;
auto chunkEnd = input->getPosition() + length + (length & 1);
len = (uint64) input->readInt64();
end = len + (uint64) startOfRIFFChunk;
dataLength = input->readInt64();
input->setPosition (chunkEnd);
}
while ((uint64) input->getPosition() < end && ! input->isExhausted())
{
auto chunkType = input->readInt();
auto length = (uint32) input->readInt();
auto chunkEnd = input->getPosition() + length + (length & 1);
if (chunkType == chunkName ("fmt "))
{
// read the format chunk
auto format = (unsigned short) input->readShort();
numChannels = (unsigned int) input->readShort();
sampleRate = input->readInt();
auto bytesPerSec = input->readInt();
input->skipNextBytes (2);
bitsPerSample = (unsigned int) (int) input->readShort();
if (bitsPerSample > 64 && (int) sampleRate != 0)
{
bytesPerFrame = bytesPerSec / (int) sampleRate;
if (numChannels != 0)
bitsPerSample = 8 * (unsigned int) bytesPerFrame / numChannels;
}
else
{
bytesPerFrame = (int) (numChannels * bitsPerSample / 8);
}
if (format == 3)
{
usesFloatingPointData = true;
}
else if (format == 0xfffe) // WAVE_FORMAT_EXTENSIBLE
{
if (length < 40) // too short
{
bytesPerFrame = 0;
}
else
{
input->skipNextBytes (4); // skip over size and bitsPerSample
auto channelMask = input->readInt();
dict["ChannelMask"] = String (channelMask);
channelLayout = getChannelLayoutFromMask (channelMask, numChannels);
ExtensibleWavSubFormat subFormat;
subFormat.data1 = (uint32) input->readInt();
subFormat.data2 = (uint16) input->readShort();
subFormat.data3 = (uint16) input->readShort();
input->read (subFormat.data4, sizeof (subFormat.data4));
if (subFormat == IEEEFloatFormat)
usesFloatingPointData = true;
else if (subFormat != pcmFormat && subFormat != ambisonicFormat)
bytesPerFrame = 0;
}
}
else if (format == 0x674f // WAVE_FORMAT_OGG_VORBIS_MODE_1
|| format == 0x6750 // WAVE_FORMAT_OGG_VORBIS_MODE_2
|| format == 0x6751 // WAVE_FORMAT_OGG_VORBIS_MODE_3
|| format == 0x676f // WAVE_FORMAT_OGG_VORBIS_MODE_1_PLUS
|| format == 0x6770 // WAVE_FORMAT_OGG_VORBIS_MODE_2_PLUS
|| format == 0x6771) // WAVE_FORMAT_OGG_VORBIS_MODE_3_PLUS
{
isSubformatOggVorbis = true;
sampleRate = 0; // to mark the wav reader as failed
input->setPosition (streamStartPos);
return;
}
else if (format != 1)
{
bytesPerFrame = 0;
}
}
else if (chunkType == chunkName ("data"))
{
if (isRF64)
{
if (dataLength > 0)
chunkEnd = input->getPosition() + dataLength + (dataLength & 1);
}
else
{
dataLength = length;
}
dataChunkStart = input->getPosition();
lengthInSamples = (bytesPerFrame > 0) ? (dataLength / bytesPerFrame) : 0;
}
else if (chunkType == chunkName ("bext"))
{
bwavChunkStart = input->getPosition();
bwavSize = length;
HeapBlock<BWAVChunk> bwav;
bwav.calloc (jmax ((size_t) length + 1, sizeof (BWAVChunk)), 1);
input->read (bwav, (int) length);
bwav->copyTo (dict, (int) length);
}
else if (chunkType == chunkName ("smpl"))
{
HeapBlock<SMPLChunk> smpl;
smpl.calloc (jmax ((size_t) length + 1, sizeof (SMPLChunk)), 1);
input->read (smpl, (int) length);
smpl->copyTo (dict, (int) length);
}
else if (chunkType == chunkName ("inst") || chunkType == chunkName ("INST")) // need to check which...
{
HeapBlock<InstChunk> inst;
inst.calloc (jmax ((size_t) length + 1, sizeof (InstChunk)), 1);
input->read (inst, (int) length);
inst->copyTo (dict);
}
else if (chunkType == chunkName ("cue "))
{
HeapBlock<CueChunk> cue;
cue.calloc (jmax ((size_t) length + 1, sizeof (CueChunk)), 1);
input->read (cue, (int) length);
cue->copyTo (dict, (int) length);
}
else if (chunkType == chunkName ("axml"))
{
MemoryBlock axml;
input->readIntoMemoryBlock (axml, (ssize_t) length);
AXMLChunk::addToMetadata (dict, axml.toString());
}
else if (chunkType == chunkName ("iXML"))
{
MemoryBlock ixml;
input->readIntoMemoryBlock (ixml, (ssize_t) length);
IXMLChunk::addToMetadata (dict, ixml.toString());
}
else if (chunkType == chunkName ("LIST"))
{
auto subChunkType = input->readInt();
if (subChunkType == chunkName ("info") || subChunkType == chunkName ("INFO"))
{
ListInfoChunk::addToMetadata (dict, *input, chunkEnd);
}
else if (subChunkType == chunkName ("adtl"))
{
while (input->getPosition() < chunkEnd)
{
auto adtlChunkType = input->readInt();
auto adtlLength = (uint32) input->readInt();
auto adtlChunkEnd = input->getPosition() + (adtlLength + (adtlLength & 1));
if (adtlChunkType == chunkName ("labl") || adtlChunkType == chunkName ("note"))
{
String prefix;
if (adtlChunkType == chunkName ("labl"))
prefix << "CueLabel" << cueLabelIndex++;
else if (adtlChunkType == chunkName ("note"))
prefix << "CueNote" << cueNoteIndex++;
auto identifier = (uint32) input->readInt();
auto stringLength = (int) adtlLength - 4;
MemoryBlock textBlock;
input->readIntoMemoryBlock (textBlock, stringLength);
dict[prefix + "Identifier"] = String (identifier);
dict[prefix + "Text"] = textBlock.toString();
}
else if (adtlChunkType == chunkName ("ltxt"))
{
auto prefix = "CueRegion" + String (cueRegionIndex++);
auto identifier = (uint32) input->readInt();
auto sampleLength = (uint32) input->readInt();
auto purpose = (uint32) input->readInt();
auto country = (uint16) input->readShort();
auto language = (uint16) input->readShort();
auto dialect = (uint16) input->readShort();
auto codePage = (uint16) input->readShort();
auto stringLength = adtlLength - 20;
MemoryBlock textBlock;
input->readIntoMemoryBlock (textBlock, (int) stringLength);
dict[prefix + "Identifier"] = String (identifier);
dict[prefix + "SampleLength"] = String (sampleLength);
dict[prefix + "Purpose"] = String (purpose);
dict[prefix + "Country"] = String (country);
dict[prefix + "Language"] = String (language);
dict[prefix + "Dialect"] = String (dialect);
dict[prefix + "CodePage"] = String (codePage);
dict[prefix + "Text"] = textBlock.toString();
}
input->setPosition (adtlChunkEnd);
}
}
}
else if (chunkType == chunkName ("acid"))
{
AcidChunk (*input, length).addToMetadata (dict);
}
else if (chunkType == chunkName ("Trkn"))
{
MemoryBlock tracktion;
input->readIntoMemoryBlock (tracktion, (ssize_t) length);
dict[WavAudioFormat::tracktionLoopInfo] = tracktion.toString();
}
else if (chunkEnd <= input->getPosition())
{
break;
}
input->setPosition (chunkEnd);
}
}
if (cueLabelIndex > 0) dict["NumCueLabels"] = String (cueLabelIndex);
if (cueNoteIndex > 0) dict["NumCueNotes"] = String (cueNoteIndex);
if (cueRegionIndex > 0) dict["NumCueRegions"] = String (cueRegionIndex);
if (dict.size() > 0) dict["MetaDataSource"] = "WAV";
metadataValues.addUnorderedMap (dict);
}
//==============================================================================
bool readSamples (int* const* destSamples, int numDestChannels, int startOffsetInDestBuffer,
int64 startSampleInFile, int numSamples) override
{
clearSamplesBeyondAvailableLength (destSamples, numDestChannels, startOffsetInDestBuffer,
startSampleInFile, numSamples, lengthInSamples);
if (numSamples <= 0)
return true;
input->setPosition (dataChunkStart + startSampleInFile * bytesPerFrame);
while (numSamples > 0)
{
const int tempBufSize = 480 * 3 * 4; // (keep this a multiple of 3)
char tempBuffer[tempBufSize];
auto numThisTime = jmin (tempBufSize / bytesPerFrame, numSamples);
auto bytesRead = input->read (tempBuffer, numThisTime * bytesPerFrame);
if (bytesRead < numThisTime * bytesPerFrame)
{
jassert (bytesRead >= 0);
zeromem (tempBuffer + bytesRead, (size_t) (numThisTime * bytesPerFrame - bytesRead));
}
copySampleData (bitsPerSample, usesFloatingPointData,
destSamples, startOffsetInDestBuffer, numDestChannels,
tempBuffer, (int) numChannels, numThisTime);
startOffsetInDestBuffer += numThisTime;
numSamples -= numThisTime;
}
return true;
}
static void copySampleData (unsigned int numBitsPerSample, const bool floatingPointData,
int* const* destSamples, int startOffsetInDestBuffer, int numDestChannels,
const void* sourceData, int numberOfChannels, int numSamples) noexcept
{
switch (numBitsPerSample)
{
case 8: ReadHelper<AudioData::Int32, AudioData::UInt8, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, sourceData, numberOfChannels, numSamples); break;
case 16: ReadHelper<AudioData::Int32, AudioData::Int16, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, sourceData, numberOfChannels, numSamples); break;
case 24: ReadHelper<AudioData::Int32, AudioData::Int24, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, sourceData, numberOfChannels, numSamples); break;
case 32: if (floatingPointData) ReadHelper<AudioData::Float32, AudioData::Float32, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, sourceData, numberOfChannels, numSamples);
else ReadHelper<AudioData::Int32, AudioData::Int32, AudioData::LittleEndian>::read (destSamples, startOffsetInDestBuffer, numDestChannels, sourceData, numberOfChannels, numSamples);
break;
default: jassertfalse; break;
}
}
//==============================================================================
AudioChannelSet getChannelLayout() override
{
if (channelLayout.size() == static_cast<int> (numChannels))
return channelLayout;
return WavFileHelpers::canonicalWavChannelSet (static_cast<int> (numChannels));
}
static AudioChannelSet getChannelLayoutFromMask (int dwChannelMask, size_t totalNumChannels)
{
AudioChannelSet wavFileChannelLayout;
// AudioChannelSet and wav's dwChannelMask are compatible
BigInteger channelBits (dwChannelMask);
for (auto bit = channelBits.findNextSetBit (0); bit >= 0; bit = channelBits.findNextSetBit (bit + 1))
wavFileChannelLayout.addChannel (static_cast<AudioChannelSet::ChannelType> (bit + 1));
// channel layout and number of channels do not match
if (wavFileChannelLayout.size() != static_cast<int> (totalNumChannels))
{
// for backward compatibility with old wav files, assume 1 or 2
// channel wav files are mono/stereo respectively
if (totalNumChannels <= 2 && dwChannelMask == 0)
wavFileChannelLayout = AudioChannelSet::canonicalChannelSet (static_cast<int> (totalNumChannels));
else
{
auto discreteSpeaker = static_cast<int> (AudioChannelSet::discreteChannel0);
while (wavFileChannelLayout.size() < static_cast<int> (totalNumChannels))
wavFileChannelLayout.addChannel (static_cast<AudioChannelSet::ChannelType> (discreteSpeaker++));
}
}
return wavFileChannelLayout;
}
int64 bwavChunkStart = 0, bwavSize = 0;
int64 dataChunkStart = 0, dataLength = 0;
int bytesPerFrame = 0;
bool isRF64 = false;
bool isSubformatOggVorbis = false;
AudioChannelSet channelLayout;
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WavAudioFormatReader)
};
//==============================================================================
class WavAudioFormatWriter final : public AudioFormatWriter
{
public:
WavAudioFormatWriter (OutputStream* const out, const double rate,
const AudioChannelSet& channelLayoutToUse, const unsigned int bits,
const StringPairArray& metadataValues)
: AudioFormatWriter (out, wavFormatName, rate, channelLayoutToUse, bits)
{
using namespace WavFileHelpers;
if (metadataValues.size() > 0)
{
// The meta data should have been sanitised for the WAV format.
// If it was originally sourced from an AIFF file the MetaDataSource
// key should be removed (or set to "WAV") once this has been done
jassert (metadataValues.getValue ("MetaDataSource", "None") != "AIFF");
const auto map = toMap (metadataValues);
bwavChunk = BWAVChunk::createFrom (map);
ixmlChunk = IXMLChunk::createFrom (map);
axmlChunk = AXMLChunk::createFrom (map);
smplChunk = SMPLChunk::createFrom (map);
instChunk = InstChunk::createFrom (map);
cueChunk = CueChunk ::createFrom (map);
listChunk = ListChunk::createFrom (map);
listInfoChunk = ListInfoChunk::createFrom (map);
acidChunk = AcidChunk::createFrom (map);
trckChunk = TracktionChunk::createFrom (map);
}
headerPosition = out->getPosition();
writeHeader();
}
~WavAudioFormatWriter() override
{
writeHeader();
}
//==============================================================================
bool write (const int** data, int numSamples) override
{
jassert (numSamples >= 0);
jassert (data != nullptr && *data != nullptr); // the input must contain at least one channel!
if (writeFailed)
return false;
auto bytes = numChannels * (size_t) numSamples * bitsPerSample / 8;
tempBlock.ensureSize (bytes, false);
switch (bitsPerSample)
{
case 8: WriteHelper<AudioData::UInt8, AudioData::Int32, AudioData::LittleEndian>::write (tempBlock.getData(), (int) numChannels, data, numSamples); break;
case 16: WriteHelper<AudioData::Int16, AudioData::Int32, AudioData::LittleEndian>::write (tempBlock.getData(), (int) numChannels, data, numSamples); break;
case 24: WriteHelper<AudioData::Int24, AudioData::Int32, AudioData::LittleEndian>::write (tempBlock.getData(), (int) numChannels, data, numSamples); break;
case 32: WriteHelper<AudioData::Int32, AudioData::Int32, AudioData::LittleEndian>::write (tempBlock.getData(), (int) numChannels, data, numSamples); break;
default: jassertfalse; break;
}
if (! output->write (tempBlock.getData(), bytes))
{
// failed to write to disk, so let's try writing the header.
// If it's just run out of disk space, then if it does manage
// to write the header, we'll still have a usable file..
writeHeader();
writeFailed = true;
return false;
}
bytesWritten += bytes;
lengthInSamples += (uint64) numSamples;
return true;
}
bool flush() override
{
auto lastWritePos = output->getPosition();
writeHeader();
if (output->setPosition (lastWritePos))
return true;
// if this fails, you've given it an output stream that can't seek! It needs
// to be able to seek back to write the header
jassertfalse;
return false;
}
private:
MemoryBlock tempBlock, bwavChunk, ixmlChunk, axmlChunk, smplChunk, instChunk, cueChunk, listChunk, listInfoChunk, acidChunk, trckChunk;
uint64 lengthInSamples = 0, bytesWritten = 0;
int64 headerPosition = 0;
bool writeFailed = false;
void writeHeader()
{
if ((bytesWritten & 1) != 0) // pad to an even length
output->writeByte (0);
using namespace WavFileHelpers;
if (headerPosition != output->getPosition() && ! output->setPosition (headerPosition))
{
// if this fails, you've given it an output stream that can't seek! It needs to be
// able to seek back to go back and write the header after the data has been written.
jassertfalse;
return;
}
const size_t bytesPerFrame = numChannels * bitsPerSample / 8;
uint64 audioDataSize = bytesPerFrame * lengthInSamples;
auto channelMask = getChannelMaskFromChannelLayout (channelLayout);
const bool isRF64 = (bytesWritten >= 0x100000000LL);
const bool isWaveFmtEx = isRF64 || (channelMask != 0);
int64 riffChunkSize = (int64) (4 /* 'RIFF' */ + 8 + 40 /* WAVEFORMATEX */
+ 8 + audioDataSize + (audioDataSize & 1)
+ chunkSize (bwavChunk)
+ chunkSize (ixmlChunk)
+ chunkSize (axmlChunk)
+ chunkSize (smplChunk)
+ chunkSize (instChunk)
+ chunkSize (cueChunk)
+ chunkSize (listChunk)
+ chunkSize (listInfoChunk)
+ chunkSize (acidChunk)
+ chunkSize (trckChunk)
+ (8 + 28)); // (ds64 chunk)
riffChunkSize += (riffChunkSize & 1);
if (isRF64)
writeChunkHeader (chunkName ("RF64"), -1);
else
writeChunkHeader (chunkName ("RIFF"), (int) riffChunkSize);
output->writeInt (chunkName ("WAVE"));
if (! isRF64)
{
#if ! JUCE_WAV_DO_NOT_PAD_HEADER_SIZE
/* NB: This junk chunk is added for padding, so that the header is a fixed size
regardless of whether it's RF64 or not. That way, we can begin recording a file,
and when it's finished, can go back and write either a RIFF or RF64 header,
depending on whether more than 2^32 samples were written.
The JUCE_WAV_DO_NOT_PAD_HEADER_SIZE macro allows you to disable this feature in case
you need to create files for crappy WAV players with bugs that stop them skipping chunks
which they don't recognise. But DO NOT USE THIS option unless you really have no choice,
because it means that if you write more than 2^32 samples to the file, you'll corrupt it.
*/
writeChunkHeader (chunkName ("JUNK"), 28 + (isWaveFmtEx? 0 : 24));
output->writeRepeatedByte (0, 28 /* ds64 */ + (isWaveFmtEx? 0 : 24));
#endif
}
else
{
#if JUCE_WAV_DO_NOT_PAD_HEADER_SIZE
// If you disable padding, then you MUST NOT write more than 2^32 samples to a file.
jassertfalse;
#endif
writeChunkHeader (chunkName ("ds64"), 28); // chunk size for uncompressed data (no table)
output->writeInt64 (riffChunkSize);
output->writeInt64 ((int64) audioDataSize);
output->writeRepeatedByte (0, 12);
}
if (isWaveFmtEx)
{
writeChunkHeader (chunkName ("fmt "), 40);
output->writeShort ((short) (uint16) 0xfffe); // WAVE_FORMAT_EXTENSIBLE
}
else
{
writeChunkHeader (chunkName ("fmt "), 16);
output->writeShort (bitsPerSample < 32 ? (short) 1 /*WAVE_FORMAT_PCM*/
: (short) 3 /*WAVE_FORMAT_IEEE_FLOAT*/);
}
output->writeShort ((short) numChannels);
output->writeInt ((int) sampleRate);
output->writeInt ((int) ((double) bytesPerFrame * sampleRate)); // nAvgBytesPerSec
output->writeShort ((short) bytesPerFrame); // nBlockAlign
output->writeShort ((short) bitsPerSample); // wBitsPerSample
if (isWaveFmtEx)
{
output->writeShort (22); // cbSize (size of the extension)
output->writeShort ((short) bitsPerSample); // wValidBitsPerSample
output->writeInt (channelMask);
const ExtensibleWavSubFormat& subFormat = bitsPerSample < 32 ? pcmFormat : IEEEFloatFormat;
output->writeInt ((int) subFormat.data1);
output->writeShort ((short) subFormat.data2);
output->writeShort ((short) subFormat.data3);
output->write (subFormat.data4, sizeof (subFormat.data4));
}
writeChunk (bwavChunk, chunkName ("bext"));
writeChunk (ixmlChunk, chunkName ("iXML"));
writeChunk (axmlChunk, chunkName ("axml"));
writeChunk (smplChunk, chunkName ("smpl"));
writeChunk (instChunk, chunkName ("inst"), 7);
writeChunk (cueChunk, chunkName ("cue "));
writeChunk (listChunk, chunkName ("LIST"));
writeChunk (listInfoChunk, chunkName ("LIST"));
writeChunk (acidChunk, chunkName ("acid"));
writeChunk (trckChunk, chunkName ("Trkn"));
writeChunkHeader (chunkName ("data"), isRF64 ? -1 : (int) (lengthInSamples * bytesPerFrame));
usesFloatingPointData = (bitsPerSample == 32);
}
static size_t chunkSize (const MemoryBlock& data) noexcept { return data.isEmpty() ? 0 : (8 + data.getSize()); }
void writeChunkHeader (int chunkType, int size) const
{
output->writeInt (chunkType);
output->writeInt (size);
}
void writeChunk (const MemoryBlock& data, int chunkType, int size = 0) const
{
if (! data.isEmpty())
{
writeChunkHeader (chunkType, size != 0 ? size : (int) data.getSize());
*output << data;
}
}
static int getChannelMaskFromChannelLayout (const AudioChannelSet& layout)
{
if (layout.isDiscreteLayout())
return 0;
// Don't add an extended format chunk for mono and stereo. Basically, all wav players
// interpret a wav file with only one or two channels to be mono or stereo anyway.
if (layout == AudioChannelSet::mono() || layout == AudioChannelSet::stereo())
return 0;
auto channels = layout.getChannelTypes();
auto wavChannelMask = 0;
for (auto channel : channels)
{
int wavChannelBit = static_cast<int> (channel) - 1;
jassert (wavChannelBit >= 0 && wavChannelBit <= 31);
wavChannelMask |= (1 << wavChannelBit);
}
return wavChannelMask;
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WavAudioFormatWriter)
};
//==============================================================================
class MemoryMappedWavReader final : public MemoryMappedAudioFormatReader
{
public:
MemoryMappedWavReader (const File& wavFile, const WavAudioFormatReader& reader)
: MemoryMappedAudioFormatReader (wavFile, reader, reader.dataChunkStart,
reader.dataLength, reader.bytesPerFrame)
{
}
bool readSamples (int* const* destSamples, int numDestChannels, int startOffsetInDestBuffer,
int64 startSampleInFile, int numSamples) override
{
clearSamplesBeyondAvailableLength (destSamples, numDestChannels, startOffsetInDestBuffer,
startSampleInFile, numSamples, lengthInSamples);
if (numSamples <= 0)
return true;
if (map == nullptr || ! mappedSection.contains (Range<int64> (startSampleInFile, startSampleInFile + numSamples)))
{
jassertfalse; // you must make sure that the window contains all the samples you're going to attempt to read.
return false;
}
WavAudioFormatReader::copySampleData (bitsPerSample, usesFloatingPointData,
destSamples, startOffsetInDestBuffer, numDestChannels,
sampleToPointer (startSampleInFile), (int) numChannels, numSamples);
return true;
}
void getSample (int64 sample, float* result) const noexcept override
{
auto num = (int) numChannels;
if (map == nullptr || ! mappedSection.contains (sample))
{
jassertfalse; // you must make sure that the window contains all the samples you're going to attempt to read.
zeromem (result, (size_t) num * sizeof (float));
return;
}
auto dest = &result;
auto source = sampleToPointer (sample);
switch (bitsPerSample)
{
case 8: ReadHelper<AudioData::Float32, AudioData::UInt8, AudioData::LittleEndian>::read (dest, 0, 1, source, 1, num); break;
case 16: ReadHelper<AudioData::Float32, AudioData::Int16, AudioData::LittleEndian>::read (dest, 0, 1, source, 1, num); break;
case 24: ReadHelper<AudioData::Float32, AudioData::Int24, AudioData::LittleEndian>::read (dest, 0, 1, source, 1, num); break;
case 32: if (usesFloatingPointData) ReadHelper<AudioData::Float32, AudioData::Float32, AudioData::LittleEndian>::read (dest, 0, 1, source, 1, num);
else ReadHelper<AudioData::Float32, AudioData::Int32, AudioData::LittleEndian>::read (dest, 0, 1, source, 1, num);
break;
default: jassertfalse; break;
}
}
void readMaxLevels (int64 startSampleInFile, int64 numSamples, Range<float>* results, int numChannelsToRead) override
{
numSamples = jmin (numSamples, lengthInSamples - startSampleInFile);
if (map == nullptr || numSamples <= 0 || ! mappedSection.contains (Range<int64> (startSampleInFile, startSampleInFile + numSamples)))
{
jassert (numSamples <= 0); // you must make sure that the window contains all the samples you're going to attempt to read.
for (int i = 0; i < numChannelsToRead; ++i)
results[i] = {};
return;
}
switch (bitsPerSample)
{
case 8: scanMinAndMax<AudioData::UInt8> (startSampleInFile, numSamples, results, numChannelsToRead); break;
case 16: scanMinAndMax<AudioData::Int16> (startSampleInFile, numSamples, results, numChannelsToRead); break;
case 24: scanMinAndMax<AudioData::Int24> (startSampleInFile, numSamples, results, numChannelsToRead); break;
case 32: if (usesFloatingPointData) scanMinAndMax<AudioData::Float32> (startSampleInFile, numSamples, results, numChannelsToRead);
else scanMinAndMax<AudioData::Int32> (startSampleInFile, numSamples, results, numChannelsToRead);
break;
default: jassertfalse; break;
}
}
using AudioFormatReader::readMaxLevels;
private:
template <typename SampleType>
void scanMinAndMax (int64 startSampleInFile, int64 numSamples, Range<float>* results, int numChannelsToRead) const noexcept
{
for (int i = 0; i < numChannelsToRead; ++i)
results[i] = scanMinAndMaxInterleaved<SampleType, AudioData::LittleEndian> (i, startSampleInFile, numSamples);
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryMappedWavReader)
};
//==============================================================================
WavAudioFormat::WavAudioFormat() : AudioFormat (wavFormatName, ".wav .bwf") {}
WavAudioFormat::~WavAudioFormat() {}
Array<int> WavAudioFormat::getPossibleSampleRates()
{
return { 8000, 11025, 12000, 16000, 22050, 32000, 44100,
48000, 88200, 96000, 176400, 192000, 352800, 384000 };
}
Array<int> WavAudioFormat::getPossibleBitDepths()
{
return { 8, 16, 24, 32 };
}
bool WavAudioFormat::canDoStereo() { return true; }
bool WavAudioFormat::canDoMono() { return true; }
bool WavAudioFormat::isChannelLayoutSupported (const AudioChannelSet& channelSet)
{
auto channelTypes = channelSet.getChannelTypes();
// When
if (channelSet.isDiscreteLayout())
return true;
// WAV supports all channel types from left ... topRearRight
for (auto channel : channelTypes)
if (channel < AudioChannelSet::left || channel > AudioChannelSet::topRearRight)
return false;
return true;
}
AudioFormatReader* WavAudioFormat::createReaderFor (InputStream* sourceStream, bool deleteStreamIfOpeningFails)
{
std::unique_ptr<WavAudioFormatReader> r (new WavAudioFormatReader (sourceStream));
#if JUCE_USE_OGGVORBIS
if (r->isSubformatOggVorbis)
{
r->input = nullptr;
return OggVorbisAudioFormat().createReaderFor (sourceStream, deleteStreamIfOpeningFails);
}
#endif
if (r->sampleRate > 0 && r->numChannels > 0 && r->bytesPerFrame > 0 && r->bitsPerSample <= 32)
return r.release();
if (! deleteStreamIfOpeningFails)
r->input = nullptr;
return nullptr;
}
MemoryMappedAudioFormatReader* WavAudioFormat::createMemoryMappedReader (const File& file)
{
return createMemoryMappedReader (file.createInputStream().release());
}
MemoryMappedAudioFormatReader* WavAudioFormat::createMemoryMappedReader (FileInputStream* fin)
{
if (fin != nullptr)
{
WavAudioFormatReader reader (fin);
if (reader.lengthInSamples > 0)
return new MemoryMappedWavReader (fin->getFile(), reader);
}
return nullptr;
}
AudioFormatWriter* WavAudioFormat::createWriterFor (OutputStream* out, double sampleRate,
unsigned int numChannels, int bitsPerSample,
const StringPairArray& metadataValues, int qualityOptionIndex)
{
return createWriterFor (out, sampleRate, WavFileHelpers::canonicalWavChannelSet (static_cast<int> (numChannels)),
bitsPerSample, metadataValues, qualityOptionIndex);
}
AudioFormatWriter* WavAudioFormat::createWriterFor (OutputStream* out,
double sampleRate,
const AudioChannelSet& channelLayout,
int bitsPerSample,
const StringPairArray& metadataValues,
int /*qualityOptionIndex*/)
{
if (out != nullptr && getPossibleBitDepths().contains (bitsPerSample) && isChannelLayoutSupported (channelLayout))
return new WavAudioFormatWriter (out, sampleRate, channelLayout,
(unsigned int) bitsPerSample, metadataValues);
return nullptr;
}
namespace WavFileHelpers
{
static bool slowCopyWavFileWithNewMetadata (const File& file, const StringPairArray& metadata)
{
TemporaryFile tempFile (file);
WavAudioFormat wav;
std::unique_ptr<AudioFormatReader> reader (wav.createReaderFor (file.createInputStream().release(), true));
if (reader != nullptr)
{
std::unique_ptr<OutputStream> outStream (tempFile.getFile().createOutputStream());
if (outStream != nullptr)
{
std::unique_ptr<AudioFormatWriter> writer (wav.createWriterFor (outStream.get(), reader->sampleRate,
reader->numChannels, (int) reader->bitsPerSample,
metadata, 0));
if (writer != nullptr)
{
outStream.release();
bool ok = writer->writeFromAudioReader (*reader, 0, -1);
writer.reset();
reader.reset();
return ok && tempFile.overwriteTargetFileWithTemporary();
}
}
}
return false;
}
}
bool WavAudioFormat::replaceMetadataInFile (const File& wavFile, const StringPairArray& newMetadata)
{
using namespace WavFileHelpers;
std::unique_ptr<WavAudioFormatReader> reader (static_cast<WavAudioFormatReader*> (createReaderFor (wavFile.createInputStream().release(), true)));
if (reader != nullptr)
{
auto bwavPos = reader->bwavChunkStart;
auto bwavSize = reader->bwavSize;
reader.reset();
if (bwavSize > 0)
{
auto chunk = BWAVChunk::createFrom (toMap (newMetadata));
if (chunk.getSize() <= (size_t) bwavSize)
{
// the new one will fit in the space available, so write it directly..
auto oldSize = wavFile.getSize();
{
FileOutputStream out (wavFile);
if (out.openedOk())
{
out.setPosition (bwavPos);
out << chunk;
out.setPosition (oldSize);
}
}
jassert (wavFile.getSize() == oldSize);
return true;
}
}
}
return slowCopyWavFileWithNewMetadata (wavFile, newMetadata);
}
//==============================================================================
//==============================================================================
#if JUCE_UNIT_TESTS
struct WaveAudioFormatTests final : public UnitTest
{
WaveAudioFormatTests()
: UnitTest ("Wave audio format tests", UnitTestCategories::audio)
{}
void runTest() override
{
beginTest ("Setting up metadata");
auto metadataValues = toMap (WavAudioFormat::createBWAVMetadata ("description",
"originator",
"originatorRef",
Time::getCurrentTime(),
numTestAudioBufferSamples,
"codingHistory"));
for (int i = numElementsInArray (WavFileHelpers::ListInfoChunk::types); --i >= 0;)
metadataValues[WavFileHelpers::ListInfoChunk::types[i]] = WavFileHelpers::ListInfoChunk::types[i];
metadataValues[WavAudioFormat::internationalStandardRecordingCode] = WavAudioFormat::internationalStandardRecordingCode;
if (metadataValues.size() > 0)
metadataValues["MetaDataSource"] = "WAV";
const auto smplMetadata = createDefaultSMPLMetadata();
metadataValues.insert (smplMetadata.cbegin(), smplMetadata.cend());
WavAudioFormat format;
MemoryBlock memoryBlock;
StringPairArray metadataArray;
metadataArray.addUnorderedMap (metadataValues);
{
beginTest ("Metadata can be written and read");
const auto newMetadata = getMetadataAfterReading (format, writeToBlock (format, metadataArray));
expect (newMetadata == metadataArray, "Somehow, the metadata is different!");
}
{
beginTest ("Files containing a riff info source and an empty ISRC associate the source with the riffInfoSource key");
StringPairArray meta;
meta.addMap ({ { WavAudioFormat::riffInfoSource, "customsource" },
{ WavAudioFormat::internationalStandardRecordingCode, "" } });
const auto mb = writeToBlock (format, meta);
checkPatternsPresent (mb, { "INFOISRC" });
checkPatternsNotPresent (mb, { "ISRC:", "<ebucore" });
const auto a = getMetadataAfterReading (format, mb);
expect (a[WavAudioFormat::riffInfoSource] == "customsource");
expect (a[WavAudioFormat::internationalStandardRecordingCode] == "");
}
{
beginTest ("Files containing a riff info source and no ISRC associate the source with both keys "
"for backwards compatibility");
StringPairArray meta;
meta.addMap ({ { WavAudioFormat::riffInfoSource, "customsource" } });
const auto mb = writeToBlock (format, meta);
checkPatternsPresent (mb, { "INFOISRC", "ISRC:customsource", "<ebucore" });
const auto a = getMetadataAfterReading (format, mb);
expect (a[WavAudioFormat::riffInfoSource] == "customsource");
expect (a[WavAudioFormat::internationalStandardRecordingCode] == "customsource");
}
{
beginTest ("Files containing an ISRC associate the value with the internationalStandardRecordingCode key "
"and the riffInfoSource key for backwards compatibility");
StringPairArray meta;
meta.addMap ({ { WavAudioFormat::internationalStandardRecordingCode, "AABBBCCDDDDD" } });
const auto mb = writeToBlock (format, meta);
checkPatternsPresent (mb, { "ISRC:AABBBCCDDDDD", "<ebucore" });
checkPatternsNotPresent (mb, { "INFOISRC" });
const auto a = getMetadataAfterReading (format, mb);
expect (a[WavAudioFormat::riffInfoSource] == "AABBBCCDDDDD");
expect (a[WavAudioFormat::internationalStandardRecordingCode] == "AABBBCCDDDDD");
}
{
beginTest ("Files containing an ISRC and a riff info source associate the values with the appropriate keys");
StringPairArray meta;
meta.addMap ({ { WavAudioFormat::riffInfoSource, "source" } });
meta.addMap ({ { WavAudioFormat::internationalStandardRecordingCode, "UUVVVXXYYYYY" } });
const auto mb = writeToBlock (format, meta);
checkPatternsPresent (mb, { "INFOISRC", "ISRC:UUVVVXXYYYYY", "<ebucore" });
const auto a = getMetadataAfterReading (format, mb);
expect (a[WavAudioFormat::riffInfoSource] == "source");
expect (a[WavAudioFormat::internationalStandardRecordingCode] == "UUVVVXXYYYYY");
}
{
beginTest ("Files containing ASWG metadata read and write correctly");
MemoryBlock block;
StringPairArray meta;
for (const auto& key : WavFileHelpers::IXMLChunk::aswgMetadataKeys)
meta.set (key, "Test123&<>");
{
auto writer = rawToUniquePtr (WavAudioFormat().createWriterFor (new MemoryOutputStream (block, false), 48000, 1, 32, meta, 0));
expect (writer != nullptr);
}
expect ([&]
{
auto input = std::make_unique<MemoryInputStream> (block, false);
while (! input->isExhausted())
{
char chunkType[4] {};
auto pos = input->getPosition();
input->read (chunkType, 4);
if (memcmp (chunkType, "iXML", 4) == 0)
{
auto length = (uint32) input->readInt();
MemoryBlock xmlBlock;
input->readIntoMemoryBlock (xmlBlock, (ssize_t) length);
return parseXML (xmlBlock.toString()) != nullptr;
}
input->setPosition (pos + 1);
}
return false;
}());
{
auto reader = rawToUniquePtr (WavAudioFormat().createReaderFor (new MemoryInputStream (block, false), true));
expect (reader != nullptr);
for (const auto& key : meta.getAllKeys())
{
const auto oldValue = meta.getValue (key, "!");
const auto newValue = reader->metadataValues.getValue (key, "");
expectEquals (oldValue, newValue);
}
expect (reader->metadataValues.getValue (WavAudioFormat::aswgVersion, "") == "3.01");
}
}
}
private:
MemoryBlock writeToBlock (WavAudioFormat& format, StringPairArray meta)
{
MemoryBlock mb;
{
// The destructor of the writer will modify the block, so make sure that we've
// destroyed the writer before returning the block!
auto writer = rawToUniquePtr (format.createWriterFor (new MemoryOutputStream (mb, false),
44100.0,
numTestAudioBufferChannels,
16,
meta,
0));
expect (writer != nullptr);
AudioBuffer<float> buffer (numTestAudioBufferChannels, numTestAudioBufferSamples);
expect (writer->writeFromAudioSampleBuffer (buffer, 0, numTestAudioBufferSamples));
}
return mb;
}
StringPairArray getMetadataAfterReading (WavAudioFormat& format, const MemoryBlock& mb)
{
auto reader = rawToUniquePtr (format.createReaderFor (new MemoryInputStream (mb, false), true));
expect (reader != nullptr);
return reader->metadataValues;
}
template <typename Fn>
void checkPatterns (const MemoryBlock& mb, const std::vector<std::string>& patterns, Fn&& fn)
{
for (const auto& pattern : patterns)
{
const auto begin = static_cast<const char*> (mb.getData());
const auto end = begin + mb.getSize();
expect (fn (std::search (begin, end, pattern.begin(), pattern.end()), end));
}
}
void checkPatternsPresent (const MemoryBlock& mb, const std::vector<std::string>& patterns)
{
checkPatterns (mb, patterns, std::not_equal_to<>{});
}
void checkPatternsNotPresent (const MemoryBlock& mb, const std::vector<std::string>& patterns)
{
checkPatterns (mb, patterns, std::equal_to<>{});
}
enum
{
numTestAudioBufferChannels = 2,
numTestAudioBufferSamples = 256
};
static StringMap createDefaultSMPLMetadata()
{
StringMap m;
m["Manufacturer"] = "0";
m["Product"] = "0";
m["SamplePeriod"] = "0";
m["MidiUnityNote"] = "60";
m["MidiPitchFraction"] = "0";
m["SmpteFormat"] = "0";
m["SmpteOffset"] = "0";
m["NumSampleLoops"] = "0";
m["SamplerData"] = "0";
return m;
}
JUCE_DECLARE_NON_COPYABLE (WaveAudioFormatTests)
};
static const WaveAudioFormatTests waveAudioFormatTests;
#endif
} // namespace juce
juce::Array
Definition juce_Array.h:56
juce::AudioChannelSet
Definition juce_AudioChannelSet.h:47
juce::AudioChannelSet::quadraphonic
static AudioChannelSet JUCE_CALLTYPE quadraphonic()
Definition juce_AudioChannelSet.cpp:553
juce::AudioChannelSet::create5point0
static AudioChannelSet JUCE_CALLTYPE create5point0()
Definition juce_AudioChannelSet.cpp:543
juce::AudioChannelSet::isDiscreteLayout
bool isDiscreteLayout() const noexcept
Definition juce_AudioChannelSet.cpp:474
juce::AudioChannelSet::mono
static AudioChannelSet JUCE_CALLTYPE mono()
Definition juce_AudioChannelSet.cpp:538
juce::AudioChannelSet::stereo
static AudioChannelSet JUCE_CALLTYPE stereo()
Definition juce_AudioChannelSet.cpp:539
juce::AudioChannelSet::ChannelType
ChannelType
Definition juce_AudioChannelSet.h:353
juce::AudioChannelSet::topRearRight
@ topRearRight
Definition juce_AudioChannelSet.h:377
juce::AudioChannelSet::discreteChannel0
@ discreteChannel0
Definition juce_AudioChannelSet.h:493
juce::AudioChannelSet::create5point1
static AudioChannelSet JUCE_CALLTYPE create5point1()
Definition juce_AudioChannelSet.cpp:544
juce::AudioChannelSet::create7point0SDDS
static AudioChannelSet JUCE_CALLTYPE create7point0SDDS()
Definition juce_AudioChannelSet.cpp:550
juce::AudioChannelSet::create7point1SDDS
static AudioChannelSet JUCE_CALLTYPE create7point1SDDS()
Definition juce_AudioChannelSet.cpp:552
juce::AudioChannelSet::canonicalChannelSet
static AudioChannelSet JUCE_CALLTYPE canonicalChannelSet(int numChannels)
Definition juce_AudioChannelSet.cpp:616
juce::AudioChannelSet::discreteChannels
static AudioChannelSet JUCE_CALLTYPE discreteChannels(int numChannels)
Definition juce_AudioChannelSet.cpp:609
juce::AudioChannelSet::createLCR
static AudioChannelSet JUCE_CALLTYPE createLCR()
Definition juce_AudioChannelSet.cpp:540
juce::AudioChannelSet::getChannelTypes
Array< ChannelType > getChannelTypes() const
Definition juce_AudioChannelSet.cpp:513
juce::AudioFormatReader
Definition juce_AudioFormatReader.h:44
juce::AudioFormatReader::input
InputStream * input
Definition juce_AudioFormatReader.h:248
juce::AudioFormatReader::usesFloatingPointData
bool usesFloatingPointData
Definition juce_AudioFormatReader.h:237
juce::AudioFormatReader::metadataValues
StringPairArray metadataValues
Definition juce_AudioFormatReader.h:245
juce::AudioFormatReader::clearSamplesBeyondAvailableLength
static void clearSamplesBeyondAvailableLength(int *const *destChannels, int numDestChannels, int startOffsetInDestBuffer, int64 startSampleInFile, int &numSamples, int64 fileLengthInSamples)
Definition juce_AudioFormatReader.h:309
juce::AudioFormatReader::lengthInSamples
int64 lengthInSamples
Definition juce_AudioFormatReader.h:231
juce::AudioFormatReader::sampleRate
double sampleRate
Definition juce_AudioFormatReader.h:225
juce::AudioFormatReader::getChannelLayout
virtual AudioChannelSet getChannelLayout()
Definition juce_AudioFormatReader.cpp:398
juce::AudioFormatReader::AudioFormatReader
AudioFormatReader(InputStream *sourceStream, const String &formatName)
Definition juce_AudioFormatReader.cpp:29
juce::AudioFormatReader::bitsPerSample
unsigned int bitsPerSample
Definition juce_AudioFormatReader.h:228
juce::AudioFormatReader::readMaxLevels
virtual void readMaxLevels(int64 startSample, int64 numSamples, Range< float > *results, int numChannelsToRead)
Definition juce_AudioFormatReader.cpp:209
juce::AudioFormatReader::numChannels
unsigned int numChannels
Definition juce_AudioFormatReader.h:234
juce::AudioFormatWriter
Definition juce_AudioFormatWriter.h:44
juce::AudioFormatWriter::numChannels
unsigned int numChannels
Definition juce_AudioFormatWriter.h:251
juce::AudioFormatWriter::sampleRate
double sampleRate
Definition juce_AudioFormatWriter.h:248
juce::AudioFormatWriter::usesFloatingPointData
bool usesFloatingPointData
Definition juce_AudioFormatWriter.h:257
juce::AudioFormatWriter::flush
virtual bool flush()
Definition juce_AudioFormatWriter.cpp:208
juce::AudioFormatWriter::bitsPerSample
unsigned int bitsPerSample
Definition juce_AudioFormatWriter.h:254
juce::AudioFormatWriter::AudioFormatWriter
AudioFormatWriter(OutputStream *destStream, const String &formatName, double sampleRate, unsigned int numberOfChannels, unsigned int bitsPerSample)
Definition juce_AudioFormatWriter.cpp:29
juce::AudioFormatWriter::channelLayout
AudioChannelSet channelLayout
Definition juce_AudioFormatWriter.h:260
juce::AudioFormatWriter::output
OutputStream * output
Definition juce_AudioFormatWriter.h:263
juce::AudioFormat::AudioFormat
AudioFormat(String formatName, StringArray fileExtensions)
Definition juce_AudioFormat.cpp:29
juce::ByteOrder::littleEndianInt
static constexpr uint32 littleEndianInt(const void *bytes) noexcept
Definition juce_ByteOrder.h:199
juce::ByteOrder::swap
static constexpr uint16 swap(uint16 value) noexcept
Definition juce_ByteOrder.h:143
juce::ByteOrder::swapIfBigEndian
static Type swapIfBigEndian(Type value) noexcept
Definition juce_ByteOrder.h:63
juce::CharacterFunctions::toUpperCase
static juce_wchar toUpperCase(juce_wchar character) noexcept
Definition juce_CharacterFunctions.cpp:28
juce::FileInputStream
Definition juce_FileInputStream.h:35
juce::FileInputStream::getFile
const File & getFile() const noexcept
Definition juce_FileInputStream.h:51
juce::FileOutputStream
Definition juce_FileOutputStream.h:35
juce::FileOutputStream::setPosition
bool setPosition(int64) override
Definition juce_FileOutputStream.cpp:46
juce::FileOutputStream::openedOk
bool openedOk() const noexcept
Definition juce_FileOutputStream.h:91
juce::File
Definition juce_File.h:45
juce::File::getSize
int64 getSize() const
juce::File::createInputStream
std::unique_ptr< FileInputStream > createInputStream() const
Definition juce_File.cpp:732
juce::InputStream
Definition juce_InputStream.h:37
juce::InputStream::getPosition
virtual int64 getPosition()=0
juce::InputStream::setPosition
virtual bool setPosition(int64 newPosition)=0
juce::InputStream::isExhausted
virtual bool isExhausted()=0
juce::InputStream::readIntoMemoryBlock
virtual size_t readIntoMemoryBlock(MemoryBlock &destBlock, ssize_t maxNumBytesToRead=-1)
Definition juce_InputStream.cpp:223
juce::InputStream::read
virtual int read(void *destBuffer, int maxBytesToRead)=0
juce::InputStream::readInt
virtual int readInt()
Definition juce_InputStream.cpp:88
juce::MemoryBlock
Definition juce_MemoryBlock.h:33
juce::MemoryBlock::getData
void * getData() noexcept
Definition juce_MemoryBlock.h:91
juce::MemoryBlock::getSize
size_t getSize() const noexcept
Definition juce_MemoryBlock.h:127
juce::MemoryMappedAudioFormatReader
Definition juce_MemoryMappedAudioFormatReader.h:47
juce::MemoryMappedAudioFormatReader::MemoryMappedAudioFormatReader
MemoryMappedAudioFormatReader(const File &file, const AudioFormatReader &details, int64 dataChunkStart, int64 dataChunkLength, int bytesPerFrame)
Definition juce_AudioFormatReader.cpp:404
juce::MemoryMappedAudioFormatReader::sampleToPointer
const void * sampleToPointer(int64 sample) const noexcept
Definition juce_MemoryMappedAudioFormatReader.h:98
juce::MemoryMappedAudioFormatReader::scanMinAndMaxInterleaved
Range< float > scanMinAndMaxInterleaved(int channel, int64 startSampleInFile, int64 numSamples) const noexcept
Definition juce_MemoryMappedAudioFormatReader.h:102
juce::MemoryOutputStream
Definition juce_MemoryOutputStream.h:36
juce::MemoryOutputStream::getDataSize
size_t getDataSize() const noexcept
Definition juce_MemoryOutputStream.h:80
juce::MemoryOutputStream::write
bool write(const void *, size_t) override
Definition juce_MemoryOutputStream.cpp:102
juce::MemoryOutputStream::getMemoryBlock
MemoryBlock getMemoryBlock() const
Definition juce_MemoryOutputStream.cpp:143
juce::OutputStream
Definition juce_OutputStream.h:38
juce::OutputStream::writeByte
virtual bool writeByte(char byte)
Definition juce_OutputStream.cpp:83
juce::OutputStream::writeInt
virtual bool writeInt(int value)
Definition juce_OutputStream.cpp:109
juce::StringPairArray
Definition juce_StringPairArray.h:35
juce::StringPairArray::set
void set(const String &key, const String &value)
Definition juce_StringPairArray.cpp:101
juce::String
Definition juce_String.h:53
juce::String::createStringFromData
static String createStringFromData(const void *data, int size)
Definition juce_String.cpp:1968
juce::String::fromUTF8
static String fromUTF8(const char *utf8buffer, int bufferSizeBytes=-1)
Definition juce_String.cpp:2125
juce::TemporaryFile
Definition juce_TemporaryFile.h:65
juce::Time
Definition juce_Time.h:37
juce::Time::formatted
String formatted(const String &format) const
Definition juce_Time.cpp:341
juce::UnitTest
Definition juce_UnitTest.h:70
juce::WavAudioFormat
Definition juce_WavAudioFormat.h:38
juce::WavAudioFormat::aswgRecStudio
static const char *const aswgRecStudio
Definition juce_WavAudioFormat.h:201
juce::WavAudioFormat::aswgBillingCode
static const char *const aswgBillingCode
Definition juce_WavAudioFormat.h:263
juce::WavAudioFormat::aswgMicDistance
static const char *const aswgMicDistance
Definition juce_WavAudioFormat.h:197
juce::WavAudioFormat::riffInfoCopyright
static const char *const riffInfoCopyright
Definition juce_WavAudioFormat.h:104
juce::WavAudioFormat::acidRootSet
static const char *const acidRootSet
Definition juce_WavAudioFormat.h:83
juce::WavAudioFormat::aswgUserData
static const char *const aswgUserData
Definition juce_WavAudioFormat.h:207
juce::WavAudioFormat::riffInfoDirectory
static const char *const riffInfoDirectory
Definition juce_WavAudioFormat.h:112
juce::WavAudioFormat::bwavCodingHistory
static const char *const bwavCodingHistory
Definition juce_WavAudioFormat.h:55
juce::WavAudioFormat::bwavTimeReference
static const char *const bwavTimeReference
Definition juce_WavAudioFormat.h:65
juce::WavAudioFormat::acidDiskBased
static const char *const acidDiskBased
Definition juce_WavAudioFormat.h:85
juce::WavAudioFormat::aswgEfforts
static const char *const aswgEfforts
Definition juce_WavAudioFormat.h:221
juce::WavAudioFormat::aswgMusicSup
static const char *const aswgMusicSup
Definition juce_WavAudioFormat.h:245
juce::WavAudioFormat::aswgTimeSig
static const char *const aswgTimeSig
Definition juce_WavAudioFormat.h:261
juce::WavAudioFormat::acidOneShot
static const char *const acidOneShot
Definition juce_WavAudioFormat.h:82
juce::WavAudioFormat::aswgIsDesigned
static const char *const aswgIsDesigned
Definition juce_WavAudioFormat.h:199
juce::WavAudioFormat::riffInfoOrganisation
static const char *const riffInfoOrganisation
Definition juce_WavAudioFormat.h:139
juce::WavAudioFormat::aswgCharacterName
static const char *const aswgCharacterName
Definition juce_WavAudioFormat.h:226
juce::WavAudioFormat::aswgIsUnion
static const char *const aswgIsUnion
Definition juce_WavAudioFormat.h:236
juce::WavAudioFormat::aswgLibrary
static const char *const aswgLibrary
Definition juce_WavAudioFormat.h:210
juce::WavAudioFormat::riffInfoFirstLanguage
static const char *const riffInfoFirstLanguage
Definition juce_WavAudioFormat.h:121
juce::WavAudioFormat::aswgAmbisonicChnOrder
static const char *const aswgAmbisonicChnOrder
Definition juce_WavAudioFormat.h:193
juce::WavAudioFormat::aswgRecordingLoc
static const char *const aswgRecordingLoc
Definition juce_WavAudioFormat.h:198
juce::WavAudioFormat::aswgCreatorId
static const char *const aswgCreatorId
Definition juce_WavAudioFormat.h:211
juce::WavAudioFormat::riffInfoEncodedBy
static const char *const riffInfoEncodedBy
Definition juce_WavAudioFormat.h:117
juce::WavAudioFormat::riffInfoCommissioned
static const char *const riffInfoCommissioned
Definition juce_WavAudioFormat.h:103
juce::WavAudioFormat::riffInfoMusicBy
static const char *const riffInfoMusicBy
Definition juce_WavAudioFormat.h:136
juce::WavAudioFormat::riffInfoSharpness
static const char *const riffInfoSharpness
Definition juce_WavAudioFormat.h:152
juce::WavAudioFormat::aswgProducer
static const char *const aswgProducer
Definition juce_WavAudioFormat.h:244
juce::WavAudioFormat::aswgFxUsed
static const char *const aswgFxUsed
Definition juce_WavAudioFormat.h:234
juce::WavAudioFormat::riffInfoStatistics
static const char *const riffInfoStatistics
Definition juce_WavAudioFormat.h:161
juce::WavAudioFormat::riffInfoNinthLanguage
static const char *const riffInfoNinthLanguage
Definition juce_WavAudioFormat.h:137
juce::WavAudioFormat::riffInfoDefaultAudioStream
static const char *const riffInfoDefaultAudioStream
Definition juce_WavAudioFormat.h:110
juce::WavAudioFormat::riffInfoGenre
static const char *const riffInfoGenre
Definition juce_WavAudioFormat.h:123
juce::WavAudioFormat::canDoMono
bool canDoMono() override
Definition juce_WavAudioFormat.cpp:1958
juce::WavAudioFormat::riffInfoMoreInfoBannerImage
static const char *const riffInfoMoreInfoBannerImage
Definition juce_WavAudioFormat.h:132
juce::WavAudioFormat::aswgProjection
static const char *const aswgProjection
Definition juce_WavAudioFormat.h:223
juce::WavAudioFormat::riffInfoVegasVersionMajor
static const char *const riffInfoVegasVersionMajor
Definition juce_WavAudioFormat.h:171
juce::WavAudioFormat::aswgContentType
static const char *const aswgContentType
Definition juce_WavAudioFormat.h:181
juce::WavAudioFormat::aswgOriginator
static const char *const aswgOriginator
Definition juce_WavAudioFormat.h:183
juce::WavAudioFormat::riffInfoLocation
static const char *const riffInfoLocation
Definition juce_WavAudioFormat.h:128
juce::WavAudioFormat::aswgIsOst
static const char *const aswgIsOst
Definition juce_WavAudioFormat.h:254
juce::WavAudioFormat::createReaderFor
AudioFormatReader * createReaderFor(InputStream *sourceStream, bool deleteStreamIfOpeningFails) override
Definition juce_WavAudioFormat.cpp:1976
juce::WavAudioFormat::aswgRmsPower
static const char *const aswgRmsPower
Definition juce_WavAudioFormat.h:213
juce::WavAudioFormat::riffInfoRate
static const char *const riffInfoRate
Definition juce_WavAudioFormat.h:145
juce::WavAudioFormat::riffInfoCostumeDesigner
static const char *const riffInfoCostumeDesigner
Definition juce_WavAudioFormat.h:105
juce::WavAudioFormat::riffInfoVersion
static const char *const riffInfoVersion
Definition juce_WavAudioFormat.h:173
juce::WavAudioFormat::aswgActorGender
static const char *const aswgActorGender
Definition juce_WavAudioFormat.h:231
juce::WavAudioFormat::riffInfoLightness
static const char *const riffInfoLightness
Definition juce_WavAudioFormat.h:127
juce::WavAudioFormat::riffInfoProductionStudio
static const char *const riffInfoProductionStudio
Definition juce_WavAudioFormat.h:144
juce::WavAudioFormat::aswgIsLoop
static const char *const aswgIsLoop
Definition juce_WavAudioFormat.h:250
juce::WavAudioFormat::aswgState
static const char *const aswgState
Definition juce_WavAudioFormat.h:187
juce::WavAudioFormat::aswgSongTitle
static const char *const aswgSongTitle
Definition juce_WavAudioFormat.h:241
juce::WavAudioFormat::riffInfoProducedBy
static const char *const riffInfoProducedBy
Definition juce_WavAudioFormat.h:141
juce::WavAudioFormat::aswgSpecDensity
static const char *const aswgSpecDensity
Definition juce_WavAudioFormat.h:217
juce::WavAudioFormat::riffInfoEighthLanguage
static const char *const riffInfoEighthLanguage
Definition juce_WavAudioFormat.h:116
juce::WavAudioFormat::riffInfoCropped
static const char *const riffInfoCropped
Definition juce_WavAudioFormat.h:107
juce::WavAudioFormat::aswgCharacterAge
static const char *const aswgCharacterAge
Definition juce_WavAudioFormat.h:228
juce::WavAudioFormat::canDoStereo
bool canDoStereo() override
Definition juce_WavAudioFormat.cpp:1957
juce::WavAudioFormat::riffInfoRating
static const char *const riffInfoRating
Definition juce_WavAudioFormat.h:147
juce::WavAudioFormat::aswgMicType
static const char *const aswgMicType
Definition juce_WavAudioFormat.h:195
juce::WavAudioFormat::aswgIsDiegetic
static const char *const aswgIsDiegetic
Definition juce_WavAudioFormat.h:257
juce::WavAudioFormat::riffInfoURL
static const char *const riffInfoURL
Definition juce_WavAudioFormat.h:170
juce::WavAudioFormat::aswgVersion
static const char *const aswgVersion
Definition juce_WavAudioFormat.h:264
juce::WavAudioFormat::ISRC
static const char *const ISRC
Definition juce_WavAudioFormat.h:269
juce::WavAudioFormat::riffInfoMoreInfoBannerURL
static const char *const riffInfoMoreInfoBannerURL
Definition juce_WavAudioFormat.h:133
juce::WavAudioFormat::riffInfoStartTimecode
static const char *const riffInfoStartTimecode
Definition juce_WavAudioFormat.h:160
juce::WavAudioFormat::aswgLoudnessRange
static const char *const aswgLoudnessRange
Definition juce_WavAudioFormat.h:215
juce::WavAudioFormat::bwavOriginatorRef
static const char *const bwavOriginatorRef
Definition juce_WavAudioFormat.h:52
juce::WavAudioFormat::aswgChannelConfig
static const char *const aswgChannelConfig
Definition juce_WavAudioFormat.h:191
juce::WavAudioFormat::riffInfoTitle
static const char *const riffInfoTitle
Definition juce_WavAudioFormat.h:167
juce::WavAudioFormat::aswgIsFinal
static const char *const aswgIsFinal
Definition juce_WavAudioFormat.h:252
juce::WavAudioFormat::riffInfoArtist
static const char *const riffInfoArtist
Definition juce_WavAudioFormat.h:97
juce::WavAudioFormat::aswgMusicPublisher
static const char *const aswgMusicPublisher
Definition juce_WavAudioFormat.h:247
juce::WavAudioFormat::riffInfoSixthLanguage
static const char *const riffInfoSixthLanguage
Definition juce_WavAudioFormat.h:153
juce::WavAudioFormat::riffInfoSecondaryGenre
static const char *const riffInfoSecondaryGenre
Definition juce_WavAudioFormat.h:149
juce::WavAudioFormat::riffInfoFifthLanguage
static const char *const riffInfoFifthLanguage
Definition juce_WavAudioFormat.h:120
juce::WavAudioFormat::riffInfoDotsPerInch
static const char *const riffInfoDotsPerInch
Definition juce_WavAudioFormat.h:114
juce::WavAudioFormat::riffInfoDistributedBy
static const char *const riffInfoDistributedBy
Definition juce_WavAudioFormat.h:113
juce::WavAudioFormat::riffInfoStarring_ISTR
static const char *const riffInfoStarring_ISTR
Definition juce_WavAudioFormat.h:158
juce::WavAudioFormat::aswgAccent
static const char *const aswgAccent
Definition juce_WavAudioFormat.h:237
juce::WavAudioFormat::riffInfoProductName
static const char *const riffInfoProductName
Definition juce_WavAudioFormat.h:142
juce::WavAudioFormat::riffInfoKeywords
static const char *const riffInfoKeywords
Definition juce_WavAudioFormat.h:124
juce::WavAudioFormat::aswgInstrument
static const char *const aswgInstrument
Definition juce_WavAudioFormat.h:246
juce::WavAudioFormat::aswgSession
static const char *const aswgSession
Definition juce_WavAudioFormat.h:186
juce::WavAudioFormat::riffInfoRippedBy
static const char *const riffInfoRippedBy
Definition juce_WavAudioFormat.h:148
juce::WavAudioFormat::riffInfoLanguage
static const char *const riffInfoLanguage
Definition juce_WavAudioFormat.h:125
juce::WavAudioFormat::riffInfoDateTimeOriginal
static const char *const riffInfoDateTimeOriginal
Definition juce_WavAudioFormat.h:109
juce::WavAudioFormat::acidizerFlag
static const char *const acidizerFlag
Definition juce_WavAudioFormat.h:86
juce::WavAudioFormat::riffInfoBaseURL
static const char *const riffInfoBaseURL
Definition juce_WavAudioFormat.h:98
juce::WavAudioFormat::createMemoryMappedReader
MemoryMappedAudioFormatReader * createMemoryMappedReader(const File &) override
Definition juce_WavAudioFormat.cpp:1997
juce::WavAudioFormat::isChannelLayoutSupported
bool isChannelLayoutSupported(const AudioChannelSet &channelSet) override
Definition juce_WavAudioFormat.cpp:1960
juce::WavAudioFormat::aswgArtist
static const char *const aswgArtist
Definition juce_WavAudioFormat.h:240
juce::WavAudioFormat::riffInfoProductionDesigner
static const char *const riffInfoProductionDesigner
Definition juce_WavAudioFormat.h:143
juce::WavAudioFormat::acidDenominator
static const char *const acidDenominator
Definition juce_WavAudioFormat.h:89
juce::WavAudioFormat::aswgCharacterRole
static const char *const aswgCharacterRole
Definition juce_WavAudioFormat.h:229
juce::WavAudioFormat::aswgDirection
static const char *const aswgDirection
Definition juce_WavAudioFormat.h:233
juce::WavAudioFormat::aswgIsSource
static const char *const aswgIsSource
Definition juce_WavAudioFormat.h:249
juce::WavAudioFormat::aswgFxChainName
static const char *const aswgFxChainName
Definition juce_WavAudioFormat.h:190
juce::WavAudioFormat::aswgFxName
static const char *const aswgFxName
Definition juce_WavAudioFormat.h:209
juce::WavAudioFormat::aswgOriginatorStudio
static const char *const aswgOriginatorStudio
Definition juce_WavAudioFormat.h:184
juce::WavAudioFormat::riffInfoVegasVersionMinor
static const char *const riffInfoVegasVersionMinor
Definition juce_WavAudioFormat.h:172
juce::WavAudioFormat::riffInfoLength
static const char *const riffInfoLength
Definition juce_WavAudioFormat.h:126
juce::WavAudioFormat::replaceMetadataInFile
bool replaceMetadataInFile(const File &wavFile, const StringPairArray &newMetadata)
Definition juce_WavAudioFormat.cpp:2073
juce::WavAudioFormat::aswgUsageRights
static const char *const aswgUsageRights
Definition juce_WavAudioFormat.h:235
juce::WavAudioFormat::~WavAudioFormat
~WavAudioFormat() override
Definition juce_WavAudioFormat.cpp:1944
juce::WavAudioFormat::riffInfoTechnician
static const char *const riffInfoTechnician
Definition juce_WavAudioFormat.h:164
juce::WavAudioFormat::riffInfoSoftware
static const char *const riffInfoSoftware
Definition juce_WavAudioFormat.h:154
juce::WavAudioFormat::riffInfoStarring_STAR
static const char *const riffInfoStarring_STAR
Definition juce_WavAudioFormat.h:159
juce::WavAudioFormat::riffInfoDateCreated
static const char *const riffInfoDateCreated
Definition juce_WavAudioFormat.h:108
juce::WavAudioFormat::riffInfoSeventhLanguage
static const char *const riffInfoSeventhLanguage
Definition juce_WavAudioFormat.h:151
juce::WavAudioFormat::aswgActorName
static const char *const aswgActorName
Definition juce_WavAudioFormat.h:230
juce::WavAudioFormat::aswgAmbisonicFormat
static const char *const aswgAmbisonicFormat
Definition juce_WavAudioFormat.h:192
juce::WavAudioFormat::acidBeats
static const char *const acidBeats
Definition juce_WavAudioFormat.h:88
juce::WavAudioFormat::aswgMusicVersion
static const char *const aswgMusicVersion
Definition juce_WavAudioFormat.h:258
juce::WavAudioFormat::createWriterFor
AudioFormatWriter * createWriterFor(OutputStream *streamToWriteTo, double sampleRateToUse, unsigned int numberOfChannels, int bitsPerSample, const StringPairArray &metadataValues, int qualityOptionIndex) override
Definition juce_WavAudioFormat.cpp:2015
juce::WavAudioFormat::aswgMixer
static const char *const aswgMixer
Definition juce_WavAudioFormat.h:189
juce::WavAudioFormat::riffInfoLogoIconURL
static const char *const riffInfoLogoIconURL
Definition juce_WavAudioFormat.h:129
juce::WavAudioFormat::tracktionLoopInfo
static const char *const tracktionLoopInfo
Definition juce_WavAudioFormat.h:275
juce::WavAudioFormat::acidNumerator
static const char *const acidNumerator
Definition juce_WavAudioFormat.h:90
juce::WavAudioFormat::bwavOriginationDate
static const char *const bwavOriginationDate
Definition juce_WavAudioFormat.h:53
juce::WavAudioFormat::internationalStandardRecordingCode
static const char *const internationalStandardRecordingCode
Definition juce_WavAudioFormat.h:272
juce::WavAudioFormat::aswgSourceId
static const char *const aswgSourceId
Definition juce_WavAudioFormat.h:212
juce::WavAudioFormat::riffInfoComments
static const char *const riffInfoComments
Definition juce_WavAudioFormat.h:102
juce::WavAudioFormat::riffInfoNumberOfParts
static const char *const riffInfoNumberOfParts
Definition juce_WavAudioFormat.h:138
juce::WavAudioFormat::aswgVendorCategory
static const char *const aswgVendorCategory
Definition juce_WavAudioFormat.h:208
juce::WavAudioFormat::bwavDescription
static const char *const bwavDescription
Definition juce_WavAudioFormat.h:50
juce::WavAudioFormat::riffInfoSoundSchemeTitle
static const char *const riffInfoSoundSchemeTitle
Definition juce_WavAudioFormat.h:155
juce::WavAudioFormat::aswgPapr
static const char *const aswgPapr
Definition juce_WavAudioFormat.h:219
juce::WavAudioFormat::getPossibleSampleRates
Array< int > getPossibleSampleRates() override
Definition juce_WavAudioFormat.cpp:1946
juce::WavAudioFormat::aswgEditor
static const char *const aswgEditor
Definition juce_WavAudioFormat.h:188
juce::WavAudioFormat::aswgComposor
static const char *const aswgComposor
Definition juce_WavAudioFormat.h:239
juce::WavAudioFormat::aswgSubGenre
static const char *const aswgSubGenre
Definition juce_WavAudioFormat.h:243
juce::WavAudioFormat::aswgEffortType
static const char *const aswgEffortType
Definition juce_WavAudioFormat.h:222
juce::WavAudioFormat::riffInfoWatermarkURL
static const char *const riffInfoWatermarkURL
Definition juce_WavAudioFormat.h:174
juce::WavAudioFormat::aswgLoudness
static const char *const aswgLoudness
Definition juce_WavAudioFormat.h:214
juce::WavAudioFormat::riffInfoTrackNo
static const char *const riffInfoTrackNo
Definition juce_WavAudioFormat.h:168
juce::WavAudioFormat::riffInfoMedium
static const char *const riffInfoMedium
Definition juce_WavAudioFormat.h:131
juce::WavAudioFormat::acidStretch
static const char *const acidStretch
Definition juce_WavAudioFormat.h:84
juce::WavAudioFormat::getPossibleBitDepths
Array< int > getPossibleBitDepths() override
Definition juce_WavAudioFormat.cpp:1952
juce::WavAudioFormat::aswgRightsOwner
static const char *const aswgRightsOwner
Definition juce_WavAudioFormat.h:248
juce::WavAudioFormat::aswgImpulseLocation
static const char *const aswgImpulseLocation
Definition juce_WavAudioFormat.h:202
juce::WavAudioFormat::riffInfoThirdLanguage
static const char *const riffInfoThirdLanguage
Definition juce_WavAudioFormat.h:165
juce::WavAudioFormat::bwavOriginationTime
static const char *const bwavOriginationTime
Definition juce_WavAudioFormat.h:54
juce::WavAudioFormat::aswgLanguage
static const char *const aswgLanguage
Definition juce_WavAudioFormat.h:224
juce::WavAudioFormat::riffInfoArchivalLocation
static const char *const riffInfoArchivalLocation
Definition juce_WavAudioFormat.h:96
juce::WavAudioFormat::aswgTimingRestriction
static const char *const aswgTimingRestriction
Definition juce_WavAudioFormat.h:225
juce::WavAudioFormat::aswgIsrcId
static const char *const aswgIsrcId
Definition juce_WavAudioFormat.h:259
juce::WavAudioFormat::aswgIsLicensed
static const char *const aswgIsLicensed
Definition juce_WavAudioFormat.h:256
juce::WavAudioFormat::aswgCategory
static const char *const aswgCategory
Definition juce_WavAudioFormat.h:203
juce::WavAudioFormat::aswgZeroCrossRate
static const char *const aswgZeroCrossRate
Definition juce_WavAudioFormat.h:218
juce::WavAudioFormat::aswgGenre
static const char *const aswgGenre
Definition juce_WavAudioFormat.h:242
juce::WavAudioFormat::aswgMaxPeak
static const char *const aswgMaxPeak
Definition juce_WavAudioFormat.h:216
juce::WavAudioFormat::riffInfoMoreInfoText
static const char *const riffInfoMoreInfoText
Definition juce_WavAudioFormat.h:134
juce::WavAudioFormat::aswgCharacterGender
static const char *const aswgCharacterGender
Definition juce_WavAudioFormat.h:227
juce::WavAudioFormat::riffInfoCinematographer
static const char *const riffInfoCinematographer
Definition juce_WavAudioFormat.h:99
juce::WavAudioFormat::riffInfoFourthLanguage
static const char *const riffInfoFourthLanguage
Definition juce_WavAudioFormat.h:122
juce::WavAudioFormat::riffInfoSubject
static const char *const riffInfoSubject
Definition juce_WavAudioFormat.h:162
juce::WavAudioFormat::aswgEmotion
static const char *const aswgEmotion
Definition juce_WavAudioFormat.h:238
juce::WavAudioFormat::aswgInKey
static const char *const aswgInKey
Definition juce_WavAudioFormat.h:262
juce::WavAudioFormat::aswgMicConfig
static const char *const aswgMicConfig
Definition juce_WavAudioFormat.h:196
juce::WavAudioFormat::riffInfoRated
static const char *const riffInfoRated
Definition juce_WavAudioFormat.h:146
juce::WavAudioFormat::riffInfoDimension
static const char *const riffInfoDimension
Definition juce_WavAudioFormat.h:111
juce::WavAudioFormat::aswgProject
static const char *const aswgProject
Definition juce_WavAudioFormat.h:182
juce::WavAudioFormat::aswgIntensity
static const char *const aswgIntensity
Definition juce_WavAudioFormat.h:251
juce::WavAudioFormat::riffInfoEditedBy
static const char *const riffInfoEditedBy
Definition juce_WavAudioFormat.h:115
juce::WavAudioFormat::riffInfoYear
static const char *const riffInfoYear
Definition juce_WavAudioFormat.h:176
juce::WavAudioFormat::riffInfoComment2
static const char *const riffInfoComment2
Definition juce_WavAudioFormat.h:101
juce::WavAudioFormat::createBWAVMetadata
static StringPairArray createBWAVMetadata(const String &description, const String &originator, const String &originatorRef, Time dateAndTime, int64 timeReferenceSamples, const String &codingHistory)
Definition juce_WavAudioFormat.cpp:58
juce::WavAudioFormat::riffInfoTrackNumber
static const char *const riffInfoTrackNumber
Definition juce_WavAudioFormat.h:169
juce::WavAudioFormat::riffInfoEngineer
static const char *const riffInfoEngineer
Definition juce_WavAudioFormat.h:119
juce::WavAudioFormat::riffInfoWrittenBy
static const char *const riffInfoWrittenBy
Definition juce_WavAudioFormat.h:175
juce::WavAudioFormat::aswgSubCategory
static const char *const aswgSubCategory
Definition juce_WavAudioFormat.h:204
juce::WavAudioFormat::aswgText
static const char *const aswgText
Definition juce_WavAudioFormat.h:220
juce::WavAudioFormat::riffInfoTimeCode
static const char *const riffInfoTimeCode
Definition juce_WavAudioFormat.h:166
juce::WavAudioFormat::riffInfoSourceFrom
static const char *const riffInfoSourceFrom
Definition juce_WavAudioFormat.h:157
juce::WavAudioFormat::riffInfoSource
static const char *const riffInfoSource
Definition juce_WavAudioFormat.h:156
juce::WavAudioFormat::riffInfoLogoURL
static const char *const riffInfoLogoURL
Definition juce_WavAudioFormat.h:130
juce::WavAudioFormat::aswgOrderRef
static const char *const aswgOrderRef
Definition juce_WavAudioFormat.h:253
juce::WavAudioFormat::riffInfoCountry
static const char *const riffInfoCountry
Definition juce_WavAudioFormat.h:106
juce::WavAudioFormat::aswgAmbisonicNorm
static const char *const aswgAmbisonicNorm
Definition juce_WavAudioFormat.h:194
juce::WavAudioFormat::aswgUserCategory
static const char *const aswgUserCategory
Definition juce_WavAudioFormat.h:206
juce::WavAudioFormat::aswgNotes
static const char *const aswgNotes
Definition juce_WavAudioFormat.h:185
juce::WavAudioFormat::riffInfoSecondLanguage
static const char *const riffInfoSecondLanguage
Definition juce_WavAudioFormat.h:150
juce::WavAudioFormat::aswgTempo
static const char *const aswgTempo
Definition juce_WavAudioFormat.h:260
juce::WavAudioFormat::riffInfoComment
static const char *const riffInfoComment
Definition juce_WavAudioFormat.h:100
juce::WavAudioFormat::riffInfoTapeName
static const char *const riffInfoTapeName
Definition juce_WavAudioFormat.h:163
juce::WavAudioFormat::aswgDirector
static const char *const aswgDirector
Definition juce_WavAudioFormat.h:232
juce::WavAudioFormat::aswgRecEngineer
static const char *const aswgRecEngineer
Definition juce_WavAudioFormat.h:200
juce::WavAudioFormat::aswgCatId
static const char *const aswgCatId
Definition juce_WavAudioFormat.h:205
juce::WavAudioFormat::riffInfoEndTimecode
static const char *const riffInfoEndTimecode
Definition juce_WavAudioFormat.h:118
juce::WavAudioFormat::aswgIsCinematic
static const char *const aswgIsCinematic
Definition juce_WavAudioFormat.h:255
juce::WavAudioFormat::WavAudioFormat
WavAudioFormat()
Definition juce_WavAudioFormat.cpp:1943
juce::WavAudioFormat::riffInfoPart
static const char *const riffInfoPart
Definition juce_WavAudioFormat.h:140
juce::WavAudioFormat::bwavOriginator
static const char *const bwavOriginator
Definition juce_WavAudioFormat.h:51
juce::WavAudioFormat::acidTempo
static const char *const acidTempo
Definition juce_WavAudioFormat.h:91
juce::WavAudioFormat::acidRootNote
static const char *const acidRootNote
Definition juce_WavAudioFormat.h:87
juce::WavAudioFormat::riffInfoMoreInfoURL
static const char *const riffInfoMoreInfoURL
Definition juce_WavAudioFormat.h:135
juce::WavFileHelpers::ListInfoChunk
Definition juce_WavAudioFormat.cpp:679
juce::AudioFormatReader::ReadHelper
Definition juce_AudioFormatReader.h:282
juce::AudioFormatWriter::WriteHelper
Definition juce_AudioFormatWriter.h:268