Browse Source

WavAudioFormat: Attempt to avoid quadratic metadata lookups

v6.1.6
reuk 3 years ago
parent
commit
37b92f6882
No known key found for this signature in database GPG Key ID: 9ADCD339CFC98A11
1 changed files with 173 additions and 145 deletions
  1. +173
    -145
      modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp

+ 173
- 145
modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp View File

@@ -26,6 +26,24 @@
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";
//==============================================================================
@@ -177,43 +195,42 @@ namespace WavFileHelpers
uint8 reserved[190];
char codingHistory[1];
void copyTo (StringPairArray& values, const int totalSize) const
void copyTo (StringMap& values, const int totalSize) const
{
values.set (WavAudioFormat::bwavDescription, String::fromUTF8 (description, sizeof (description)));
values.set (WavAudioFormat::bwavOriginator, String::fromUTF8 (originator, sizeof (originator)));
values.set (WavAudioFormat::bwavOriginatorRef, String::fromUTF8 (originatorRef, sizeof (originatorRef)));
values.set (WavAudioFormat::bwavOriginationDate, String::fromUTF8 (originationDate, sizeof (originationDate)));
values.set (WavAudioFormat::bwavOriginationTime, String::fromUTF8 (originationTime, sizeof (originationTime)));
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.set (WavAudioFormat::bwavTimeReference, String (time));
values.set (WavAudioFormat::bwavCodingHistory,
String::fromUTF8 (codingHistory, totalSize - (int) offsetof (BWAVChunk, codingHistory)));
values[WavAudioFormat::bwavTimeReference] = String (time);
values[WavAudioFormat::bwavCodingHistory] = String::fromUTF8 (codingHistory, totalSize - (int) offsetof (BWAVChunk, codingHistory));
}
static MemoryBlock createFrom (const StringPairArray& values)
static MemoryBlock createFrom (const StringMap& values)
{
MemoryBlock data (roundUpSize (sizeof (BWAVChunk) + values[WavAudioFormat::bwavCodingHistory].getNumBytesAsUTF8()));
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..
values[WavAudioFormat::bwavDescription] .copyToUTF8 (b->description, 257);
values[WavAudioFormat::bwavOriginator] .copyToUTF8 (b->originator, 33);
values[WavAudioFormat::bwavOriginatorRef] .copyToUTF8 (b->originatorRef, 33);
values[WavAudioFormat::bwavOriginationDate].copyToUTF8 (b->originationDate, 11);
values[WavAudioFormat::bwavOriginationTime].copyToUTF8 (b->originationTime, 9);
auto time = values[WavAudioFormat::bwavTimeReference].getLargeIntValue();
// 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));
values[WavAudioFormat::bwavCodingHistory].copyToUTF8 (b->codingHistory, 0x7fffffff);
getValueWithDefault (values, WavAudioFormat::bwavCodingHistory).copyToUTF8 (b->codingHistory, 0x7fffffff);
if (b->description[0] != 0
|| b->originator[0] != 0
@@ -270,17 +287,17 @@ namespace WavFileHelpers
SampleLoop loops[1];
template <typename NameType>
static void setValue (StringPairArray& values, NameType name, uint32 val)
static void setValue (StringMap& values, NameType name, uint32 val)
{
values.set (name, String (ByteOrder::swapIfBigEndian (val)));
values[name] = String (ByteOrder::swapIfBigEndian (val));
}
static void setValue (StringPairArray& values, int prefix, const char* name, uint32 val)
static void setValue (StringMap& values, int prefix, const char* name, uint32 val)
{
setValue (values, "Loop" + String (prefix) + name, val);
}
void copyTo (StringPairArray& values, const int totalSize) const
void copyTo (StringMap& values, const int totalSize) const
{
setValue (values, "Manufacturer", manufacturer);
setValue (values, "Product", product);
@@ -307,20 +324,20 @@ namespace WavFileHelpers
}
template <typename NameType>
static uint32 getValue (const StringPairArray& values, NameType name, const char* def)
static uint32 getValue (const StringMap& values, NameType name, const char* def)
{
return ByteOrder::swapIfBigEndian ((uint32) values.getValue (name, def).getIntValue());
return ByteOrder::swapIfBigEndian ((uint32) getValueWithDefault (values, name, def).getIntValue());
}
static uint32 getValue (const StringPairArray& values, int prefix, const char* name, const char* def)
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 StringPairArray& values)
static MemoryBlock createFrom (const StringMap& values)
{
MemoryBlock data;
auto numLoops = jmin (64, values.getValue ("NumSampleLoops", "0").getIntValue());
auto numLoops = jmin (64, getValueWithDefault (values, "NumSampleLoops", "0").getIntValue());
data.setSize (roundUpSize (sizeof (SMPLChunk) + (size_t) (jmax (0, numLoops - 1)) * sizeof (SampleLoop)), true);
@@ -362,12 +379,12 @@ namespace WavFileHelpers
int8 lowVelocity;
int8 highVelocity;
static void setValue (StringPairArray& values, const char* name, int val)
static void setValue (StringMap& values, const char* name, int val)
{
values.set (name, String (val));
values[name] = String (val);
}
void copyTo (StringPairArray& values) const
void copyTo (StringMap& values) const
{
setValue (values, "MidiUnityNote", baseNote);
setValue (values, "Detune", detune);
@@ -378,17 +395,17 @@ namespace WavFileHelpers
setValue (values, "HighVelocity", highVelocity);
}
static int8 getValue (const StringPairArray& values, const char* name, const char* def)
static int8 getValue (const StringMap& values, const char* name, const char* def)
{
return (int8) values.getValue (name, def).getIntValue();
return (int8) getValueWithDefault (values, name, def).getIntValue();
}
static MemoryBlock createFrom (const StringPairArray& values)
static MemoryBlock createFrom (const StringMap& values)
{
MemoryBlock data;
auto& keys = values.getAllKeys();
if (keys.contains ("LowNote", true) && keys.contains ("HighNote", true))
if ( values.find ("LowNote") != values.cend()
&& values.find ("HighNote") != values.cend())
{
data.setSize (8, true);
auto* inst = static_cast<InstChunk*> (data.getData());
@@ -422,14 +439,14 @@ namespace WavFileHelpers
uint32 numCues;
Cue cues[1];
static void setValue (StringPairArray& values, int prefix, const char* name, uint32 val)
static void setValue (StringMap& values, int prefix, const char* name, uint32 val)
{
values.set ("Cue" + String (prefix) + name, String (ByteOrder::swapIfBigEndian (val)));
values["Cue" + String (prefix) + name] = String (ByteOrder::swapIfBigEndian (val));
}
void copyTo (StringPairArray& values, const int totalSize) const
void copyTo (StringMap& values, const int totalSize) const
{
values.set ("NumCuePoints", String (ByteOrder::swapIfBigEndian (numCues)));
values["NumCuePoints"] = String (ByteOrder::swapIfBigEndian (numCues));
for (int i = 0; i < (int) numCues; ++i)
{
@@ -445,10 +462,10 @@ namespace WavFileHelpers
}
}
static MemoryBlock createFrom (const StringPairArray& values)
static MemoryBlock createFrom (const StringMap& values)
{
MemoryBlock data;
const int numCues = values.getValue ("NumCuePoints", "0").getIntValue();
const int numCues = getValueWithDefault (values, "NumCuePoints", "0").getIntValue();
if (numCues > 0)
{
@@ -468,23 +485,23 @@ namespace WavFileHelpers
for (int i = 0; i < numCues; ++i)
{
auto prefix = "Cue" + String (i);
auto identifier = (uint32) values.getValue (prefix + "Identifier", "0").getIntValue();
auto identifier = (uint32) getValueWithDefault (values, prefix + "Identifier", "0").getIntValue();
#if JUCE_DEBUG
jassert (! identifiers.contains (identifier));
identifiers.add (identifier);
#endif
auto order = values.getValue (prefix + "Order", String (nextOrder)).getIntValue();
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) values.getValue (prefix + "ChunkID", dataChunkID).getIntValue());
cue.chunkStart = ByteOrder::swapIfBigEndian ((uint32) values.getValue (prefix + "ChunkStart", "0").getIntValue());
cue.blockStart = ByteOrder::swapIfBigEndian ((uint32) values.getValue (prefix + "BlockStart", "0").getIntValue());
cue.offset = ByteOrder::swapIfBigEndian ((uint32) values.getValue (prefix + "Offset", "0").getIntValue());
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());
}
}
@@ -496,20 +513,20 @@ namespace WavFileHelpers
//==============================================================================
namespace ListChunk
{
static int getValue (const StringPairArray& values, const String& name)
static int getValue (const StringMap& values, const String& name)
{
return values.getValue (name, "0").getIntValue();
return getValueWithDefault (values, name, "0").getIntValue();
}
static int getValue (const StringPairArray& values, const String& prefix, const char* name)
static int getValue (const StringMap& values, const String& prefix, const char* name)
{
return getValue (values, prefix + name);
}
static void appendLabelOrNoteChunk (const StringPairArray& values, const String& prefix,
static void appendLabelOrNoteChunk (const StringMap& values, const String& prefix,
const int chunkType, MemoryOutputStream& out)
{
auto label = values.getValue (prefix + "Text", prefix);
auto label = getValueWithDefault (values, prefix + "Text", prefix);
auto labelLength = (int) label.getNumBytesAsUTF8() + 1;
auto chunkLength = 4 + labelLength + (labelLength & 1);
@@ -522,9 +539,9 @@ namespace WavFileHelpers
out.writeByte (0);
}
static void appendExtraChunk (const StringPairArray& values, const String& prefix, MemoryOutputStream& out)
static void appendExtraChunk (const StringMap& values, const String& prefix, MemoryOutputStream& out)
{
auto text = values.getValue (prefix + "Text", prefix);
auto text = getValueWithDefault (values, prefix + "Text", prefix);
auto textLength = (int) text.getNumBytesAsUTF8() + 1; // include null terminator
auto chunkLength = textLength + 20 + (textLength & 1);
@@ -544,7 +561,7 @@ namespace WavFileHelpers
out.writeByte (0);
}
static MemoryBlock createFrom (const StringPairArray& values)
static MemoryBlock createFrom (const StringMap& values)
{
auto numCueLabels = getValue (values, "NumCueLabels");
auto numCueNotes = getValue (values, "NumCueNotes");
@@ -668,7 +685,7 @@ namespace WavFileHelpers
return true;
}
static void addToMetadata (StringPairArray& values, InputStream& input, int64 chunkEnd)
static void addToMetadata (StringMap& values, InputStream& input, int64 chunkEnd)
{
while (input.getPosition() < chunkEnd)
{
@@ -688,8 +705,8 @@ namespace WavFileHelpers
{
MemoryBlock mb;
input.readIntoMemoryBlock (mb, (ssize_t) infoLength);
values.set (type, String::createStringFromData ((const char*) mb.getData(),
(int) mb.getSize()));
values[type] = String::createStringFromData ((const char*) mb.getData(),
(int) mb.getSize());
break;
}
}
@@ -697,9 +714,9 @@ namespace WavFileHelpers
}
}
static bool writeValue (const StringPairArray& values, MemoryOutputStream& out, const char* paramName)
static bool writeValue (const StringMap& values, MemoryOutputStream& out, const char* paramName)
{
auto value = values.getValue (paramName, {});
auto value = getValueWithDefault (values, paramName, {});
if (value.isEmpty())
return false;
@@ -717,7 +734,7 @@ namespace WavFileHelpers
return true;
}
static MemoryBlock createFrom (const StringPairArray& values)
static MemoryBlock createFrom (const StringMap& values)
{
MemoryOutputStream out;
out.writeInt (chunkName ("INFO"));
@@ -741,7 +758,7 @@ namespace WavFileHelpers
input.read (this, (int) jmin (sizeof (*this), length));
}
AcidChunk (const StringPairArray& values)
AcidChunk (const StringMap& values)
{
zerostruct (*this);
@@ -751,18 +768,20 @@ namespace WavFileHelpers
| getFlagIfPresent (values, WavAudioFormat::acidDiskBased, 0x08)
| getFlagIfPresent (values, WavAudioFormat::acidizerFlag, 0x10);
if (values[WavAudioFormat::acidRootSet].getIntValue() != 0)
rootNote = ByteOrder::swapIfBigEndian ((uint16) values[WavAudioFormat::acidRootNote].getIntValue());
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());
numBeats = ByteOrder::swapIfBigEndian ((uint32) values[WavAudioFormat::acidBeats].getIntValue());
meterDenominator = ByteOrder::swapIfBigEndian ((uint16) values[WavAudioFormat::acidDenominator].getIntValue());
meterNumerator = ByteOrder::swapIfBigEndian ((uint16) values[WavAudioFormat::acidNumerator].getIntValue());
const auto iter = values.find (WavAudioFormat::acidTempo);
if (values.containsKey (WavAudioFormat::acidTempo))
tempo = swapFloatByteOrder (values[WavAudioFormat::acidTempo].getFloatValue());
if (iter != values.cend())
tempo = swapFloatByteOrder (iter->second.getFloatValue());
}
static MemoryBlock createFrom (const StringPairArray& values)
static MemoryBlock createFrom (const StringMap& values)
{
return AcidChunk (values).toMemoryBlock();
}
@@ -773,7 +792,7 @@ namespace WavFileHelpers
? MemoryBlock (this, sizeof (*this)) : MemoryBlock();
}
void addToMetadata (StringPairArray& values) const
void addToMetadata (StringMap& values) const
{
setBoolFlag (values, WavAudioFormat::acidOneShot, 0x01);
setBoolFlag (values, WavAudioFormat::acidRootSet, 0x02);
@@ -782,22 +801,22 @@ namespace WavFileHelpers
setBoolFlag (values, WavAudioFormat::acidizerFlag, 0x10);
if (flags & 0x02) // root note set
values.set (WavAudioFormat::acidRootNote, String (ByteOrder::swapIfBigEndian (rootNote)));
values[WavAudioFormat::acidRootNote] = String (ByteOrder::swapIfBigEndian (rootNote));
values.set (WavAudioFormat::acidBeats, String (ByteOrder::swapIfBigEndian (numBeats)));
values.set (WavAudioFormat::acidDenominator, String (ByteOrder::swapIfBigEndian (meterDenominator)));
values.set (WavAudioFormat::acidNumerator, String (ByteOrder::swapIfBigEndian (meterNumerator)));
values.set (WavAudioFormat::acidTempo, String (swapFloatByteOrder (tempo)));
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 (StringPairArray& values, const char* name, uint32 mask) const
void setBoolFlag (StringMap& values, const char* name, uint32 mask) const
{
values.set (name, (flags & ByteOrder::swapIfBigEndian (mask)) ? "1" : "0");
values[name] = (flags & ByteOrder::swapIfBigEndian (mask)) ? "1" : "0";
}
static uint32 getFlagIfPresent (const StringPairArray& values, const char* name, uint32 flag)
static uint32 getFlagIfPresent (const StringMap& values, const char* name, uint32 flag)
{
return values[name].getIntValue() != 0 ? ByteOrder::swapIfBigEndian (flag) : 0;
return getValueWithDefault (values, name).getIntValue() != 0 ? ByteOrder::swapIfBigEndian (flag) : 0;
}
static float swapFloatByteOrder (const float x) noexcept
@@ -826,10 +845,10 @@ namespace WavFileHelpers
//==============================================================================
struct TracktionChunk
{
static MemoryBlock createFrom (const StringPairArray& values)
static MemoryBlock createFrom (const StringMap& values)
{
MemoryOutputStream out;
auto s = values[WavAudioFormat::tracktionLoopInfo];
auto s = getValueWithDefault (values, WavAudioFormat::tracktionLoopInfo);
if (s.isNotEmpty())
{
@@ -846,7 +865,7 @@ namespace WavFileHelpers
//==============================================================================
namespace AXMLChunk
{
static void addToMetadata (StringPairArray& destValues, const String& source)
static void addToMetadata (StringMap& destValues, const String& source)
{
if (auto xml = parseXML (source))
{
@@ -861,7 +880,7 @@ namespace WavFileHelpers
auto ISRCCode = xml4->getAllSubText().fromFirstOccurrenceOf ("ISRC:", false, true);
if (ISRCCode.isNotEmpty())
destValues.set (WavAudioFormat::ISRC, ISRCCode);
destValues[WavAudioFormat::ISRC] = ISRCCode;
}
}
}
@@ -869,9 +888,9 @@ namespace WavFileHelpers
}
}
static MemoryBlock createFrom (const StringPairArray& values)
static MemoryBlock createFrom (const StringMap& values)
{
auto ISRC = values.getValue (WavAudioFormat::ISRC, {});
auto ISRC = getValueWithDefault (values, WavAudioFormat::ISRC);
MemoryOutputStream xml;
if (ISRC.isNotEmpty())
@@ -941,6 +960,8 @@ public:
int cueLabelIndex = 0;
int cueRegionIndex = 0;
StringMap dict;
auto streamStartPos = input->getPosition();
auto firstChunkType = input->readInt();
@@ -1019,7 +1040,7 @@ public:
{
input->skipNextBytes (4); // skip over size and bitsPerSample
auto channelMask = input->readInt();
metadataValues.set ("ChannelMask", String (channelMask));
dict["ChannelMask"] = String (channelMask);
channelLayout = getChannelLayoutFromMask (channelMask, numChannels);
ExtensibleWavSubFormat subFormat;
@@ -1074,34 +1095,34 @@ public:
HeapBlock<BWAVChunk> bwav;
bwav.calloc (jmax ((size_t) length + 1, sizeof (BWAVChunk)), 1);
input->read (bwav, (int) length);
bwav->copyTo (metadataValues, (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 (metadataValues, (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 (metadataValues);
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 (metadataValues, (int) length);
cue->copyTo (dict, (int) length);
}
else if (chunkType == chunkName ("axml"))
{
MemoryBlock axml;
input->readIntoMemoryBlock (axml, (ssize_t) length);
AXMLChunk::addToMetadata (metadataValues, axml.toString());
AXMLChunk::addToMetadata (dict, axml.toString());
}
else if (chunkType == chunkName ("LIST"))
{
@@ -1109,7 +1130,7 @@ public:
if (subChunkType == chunkName ("info") || subChunkType == chunkName ("INFO"))
{
ListInfoChunk::addToMetadata (metadataValues, *input, chunkEnd);
ListInfoChunk::addToMetadata (dict, *input, chunkEnd);
}
else if (subChunkType == chunkName ("adtl"))
{
@@ -1134,8 +1155,8 @@ public:
MemoryBlock textBlock;
input->readIntoMemoryBlock (textBlock, stringLength);
metadataValues.set (prefix + "Identifier", String (identifier));
metadataValues.set (prefix + "Text", textBlock.toString());
dict[prefix + "Identifier"] = String (identifier);
dict[prefix + "Text"] = textBlock.toString();
}
else if (adtlChunkType == chunkName ("ltxt"))
{
@@ -1152,14 +1173,14 @@ public:
MemoryBlock textBlock;
input->readIntoMemoryBlock (textBlock, (int) stringLength);
metadataValues.set (prefix + "Identifier", String (identifier));
metadataValues.set (prefix + "SampleLength", String (sampleLength));
metadataValues.set (prefix + "Purpose", String (purpose));
metadataValues.set (prefix + "Country", String (country));
metadataValues.set (prefix + "Language", String (language));
metadataValues.set (prefix + "Dialect", String (dialect));
metadataValues.set (prefix + "CodePage", String (codePage));
metadataValues.set (prefix + "Text", textBlock.toString());
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);
@@ -1168,13 +1189,13 @@ public:
}
else if (chunkType == chunkName ("acid"))
{
AcidChunk (*input, length).addToMetadata (metadataValues);
AcidChunk (*input, length).addToMetadata (dict);
}
else if (chunkType == chunkName ("Trkn"))
{
MemoryBlock tracktion;
input->readIntoMemoryBlock (tracktion, (ssize_t) length);
metadataValues.set (WavAudioFormat::tracktionLoopInfo, tracktion.toString());
dict[WavAudioFormat::tracktionLoopInfo] = tracktion.toString();
}
else if (chunkEnd <= input->getPosition())
{
@@ -1185,10 +1206,12 @@ public:
}
}
if (cueLabelIndex > 0) metadataValues.set ("NumCueLabels", String (cueLabelIndex));
if (cueNoteIndex > 0) metadataValues.set ("NumCueNotes", String (cueNoteIndex));
if (cueRegionIndex > 0) metadataValues.set ("NumCueRegions", String (cueRegionIndex));
if (metadataValues.size() > 0) metadataValues.set ("MetaDataSource", "WAV");
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);
}
//==============================================================================
@@ -1312,15 +1335,17 @@ public:
// key should be removed (or set to "WAV") once this has been done
jassert (metadataValues.getValue ("MetaDataSource", "None") != "AIFF");
bwavChunk = BWAVChunk::createFrom (metadataValues);
axmlChunk = AXMLChunk::createFrom (metadataValues);
smplChunk = SMPLChunk::createFrom (metadataValues);
instChunk = InstChunk::createFrom (metadataValues);
cueChunk = CueChunk ::createFrom (metadataValues);
listChunk = ListChunk::createFrom (metadataValues);
listInfoChunk = ListInfoChunk::createFrom (metadataValues);
acidChunk = AcidChunk::createFrom (metadataValues);
trckChunk = TracktionChunk::createFrom (metadataValues);
const auto map = toMap (metadataValues);
bwavChunk = BWAVChunk::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();
@@ -1792,7 +1817,7 @@ bool WavAudioFormat::replaceMetadataInFile (const File& wavFile, const StringPai
if (bwavSize > 0)
{
auto chunk = BWAVChunk::createFrom (newMetadata);
auto chunk = BWAVChunk::createFrom (toMap (newMetadata));
if (chunk.getSize() <= (size_t) bwavSize)
{
@@ -1834,31 +1859,34 @@ struct WaveAudioFormatTests : public UnitTest
{
beginTest ("Setting up metadata");
StringPairArray metadataValues = WavAudioFormat::createBWAVMetadata ("description",
"originator",
"originatorRef",
Time::getCurrentTime(),
numTestAudioBufferSamples,
"codingHistory");
auto metadataValues = toMap (WavAudioFormat::createBWAVMetadata ("description",
"originator",
"originatorRef",
Time::getCurrentTime(),
numTestAudioBufferSamples,
"codingHistory"));
for (int i = numElementsInArray (WavFileHelpers::ListInfoChunk::types); --i >= 0;)
metadataValues.set (WavFileHelpers::ListInfoChunk::types[i],
WavFileHelpers::ListInfoChunk::types[i]);
metadataValues[WavFileHelpers::ListInfoChunk::types[i]] = WavFileHelpers::ListInfoChunk::types[i];
if (metadataValues.size() > 0)
metadataValues.set ("MetaDataSource", "WAV");
metadataValues["MetaDataSource"] = "WAV";
metadataValues.addArray (createDefaultSMPLMetadata());
const auto smplMetadata = createDefaultSMPLMetadata();
metadataValues.insert (smplMetadata.cbegin(), smplMetadata.cend());
WavAudioFormat format;
MemoryBlock memoryBlock;
StringPairArray metadataArray;
metadataArray.addUnorderedMap (metadataValues);
{
beginTest ("Creating a basic wave writer");
std::unique_ptr<AudioFormatWriter> writer (format.createWriterFor (new MemoryOutputStream (memoryBlock, false),
44100.0, numTestAudioBufferChannels,
32, metadataValues, 0));
32, metadataArray, 0));
expect (writer != nullptr);
AudioBuffer<float> buffer (numTestAudioBufferChannels, numTestAudioBufferSamples);
@@ -1873,7 +1901,7 @@ struct WaveAudioFormatTests : public UnitTest
std::unique_ptr<AudioFormatReader> reader (format.createReaderFor (new MemoryInputStream (memoryBlock, false), false));
expect (reader != nullptr);
expect (reader->metadataValues == metadataValues, "Somehow, the metadata is different!");
expect (reader->metadataValues == metadataArray, "Somehow, the metadata is different!");
}
}
@@ -1884,19 +1912,19 @@ private:
numTestAudioBufferSamples = 256
};
StringPairArray createDefaultSMPLMetadata() const
static StringMap createDefaultSMPLMetadata()
{
StringPairArray m;
m.set ("Manufacturer", "0");
m.set ("Product", "0");
m.set ("SamplePeriod", "0");
m.set ("MidiUnityNote", "60");
m.set ("MidiPitchFraction", "0");
m.set ("SmpteFormat", "0");
m.set ("SmpteOffset", "0");
m.set ("NumSampleLoops", "0");
m.set ("SamplerData", "0");
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;
}


Loading…
Cancel
Save