mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Added better support for writing acid and Tracktion chunks in WavAudioFormat.
This commit is contained in:
parent
46dfd54d9a
commit
b71447b057
3 changed files with 101 additions and 15 deletions
|
|
@ -65,6 +65,7 @@ const char* const WavAudioFormat::acidNumerator = "acid numerator";
|
|||
const char* const WavAudioFormat::acidTempo = "acid tempo";
|
||||
|
||||
const char* const WavAudioFormat::ISRC = "ISRC";
|
||||
const char* const WavAudioFormat::tracktionLoopInfo = "tracktion loop info";
|
||||
|
||||
//==============================================================================
|
||||
namespace WavFileHelpers
|
||||
|
|
@ -490,30 +491,100 @@ namespace WavFileHelpers
|
|||
setBoolFlag (values, WavAudioFormat::acidizerFlag, 0x10);
|
||||
|
||||
if (flags & 0x02) // root note set
|
||||
values.set (WavAudioFormat::acidRootNote, String (rootNote));
|
||||
values.set (WavAudioFormat::acidRootNote, String (ByteOrder::swapIfBigEndian (rootNote)));
|
||||
|
||||
values.set (WavAudioFormat::acidBeats, String (numBeats));
|
||||
values.set (WavAudioFormat::acidDenominator, String (meterDenominator));
|
||||
values.set (WavAudioFormat::acidNumerator, String (meterNumerator));
|
||||
values.set (WavAudioFormat::acidTempo, String (tempo));
|
||||
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)));
|
||||
}
|
||||
|
||||
void setBoolFlag (StringPairArray& values, const char* name, int32 mask) const
|
||||
void setBoolFlag (StringPairArray& values, const char* name, uint32 mask) const
|
||||
{
|
||||
values.set (name, (flags & mask) ? "1" : "0");
|
||||
values.set (name, (flags & ByteOrder::swapIfBigEndian (mask)) ? "1" : "0");
|
||||
}
|
||||
|
||||
int32 flags;
|
||||
int16 rootNote;
|
||||
int16 reserved1;
|
||||
template<typename IntType>
|
||||
static void setIntFlagIfPresent (IntType& flag, const StringPairArray& values, const char* name)
|
||||
{
|
||||
if (values.containsKey (name))
|
||||
flag = ByteOrder::swapIfBigEndian ((IntType) values[name].getIntValue());
|
||||
}
|
||||
|
||||
static uint32 getFlagIfPresent (const StringPairArray& values, const char* name, uint32 flag)
|
||||
{
|
||||
return 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
|
||||
}
|
||||
|
||||
static MemoryBlock createFrom (const StringPairArray& values)
|
||||
{
|
||||
MemoryBlock data (sizeof (AcidChunk), true);
|
||||
AcidChunk* const acid = static_cast<AcidChunk*> (data.getData());
|
||||
|
||||
acid->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 (values[WavAudioFormat::acidRootSet].getIntValue() != 0)
|
||||
setIntFlagIfPresent (acid->rootNote, values, WavAudioFormat::acidRootNote);
|
||||
|
||||
setIntFlagIfPresent (acid->numBeats, values, WavAudioFormat::acidBeats);
|
||||
setIntFlagIfPresent (acid->meterDenominator, values, WavAudioFormat::acidDenominator);
|
||||
setIntFlagIfPresent (acid->meterNumerator, values, WavAudioFormat::acidNumerator);
|
||||
|
||||
if (values.containsKey (WavAudioFormat::acidTempo))
|
||||
acid->tempo = swapFloatByteOrder (values[WavAudioFormat::acidTempo].getFloatValue());
|
||||
|
||||
if (acid->flags == 0 && acid->rootNote == 0 && acid->numBeats == 0
|
||||
&& acid->meterDenominator == 0 && acid->meterNumerator == 0)
|
||||
return MemoryBlock();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
uint32 flags;
|
||||
uint16 rootNote;
|
||||
uint16 reserved1;
|
||||
float reserved2;
|
||||
int32 numBeats;
|
||||
int16 meterDenominator;
|
||||
int16 meterNumerator;
|
||||
uint32 numBeats;
|
||||
uint16 meterDenominator;
|
||||
uint16 meterNumerator;
|
||||
float tempo;
|
||||
|
||||
} JUCE_PACKED;
|
||||
|
||||
//==============================================================================
|
||||
struct TracktionChunk
|
||||
{
|
||||
static MemoryBlock createFrom (const StringPairArray& values)
|
||||
{
|
||||
const String s = values[WavAudioFormat::tracktionLoopInfo];
|
||||
MemoryBlock data;
|
||||
|
||||
if (s.isNotEmpty())
|
||||
{
|
||||
MemoryOutputStream os (data, false);
|
||||
os.writeString (s);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
namespace AXMLChunk
|
||||
{
|
||||
|
|
@ -816,6 +887,12 @@ public:
|
|||
{
|
||||
AcidChunk (*input, length).addToMetadata (metadataValues);
|
||||
}
|
||||
else if (chunkType == chunkName ("Trkn"))
|
||||
{
|
||||
MemoryBlock tracktion;
|
||||
input->readIntoMemoryBlock (tracktion, (ssize_t) length);
|
||||
metadataValues.set (WavAudioFormat::tracktionLoopInfo, tracktion.toString());
|
||||
}
|
||||
else if (chunkEnd <= input->getPosition())
|
||||
{
|
||||
break;
|
||||
|
|
@ -919,6 +996,8 @@ public:
|
|||
instChunk = InstChunk::createFrom (metadataValues);
|
||||
cueChunk = CueChunk ::createFrom (metadataValues);
|
||||
listChunk = ListChunk::createFrom (metadataValues);
|
||||
acidChunk = AcidChunk::createFrom (metadataValues);
|
||||
trckChunk = TracktionChunk::createFrom (metadataValues);
|
||||
}
|
||||
|
||||
headerPosition = out->getPosition();
|
||||
|
|
@ -981,7 +1060,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
MemoryBlock tempBlock, bwavChunk, axmlChunk, smplChunk, instChunk, cueChunk, listChunk;
|
||||
MemoryBlock tempBlock, bwavChunk, axmlChunk, smplChunk, instChunk, cueChunk, listChunk, acidChunk, trckChunk;
|
||||
uint64 lengthInSamples, bytesWritten;
|
||||
int64 headerPosition;
|
||||
bool writeFailed;
|
||||
|
|
@ -1033,6 +1112,8 @@ private:
|
|||
+ chunkSize (instChunk)
|
||||
+ chunkSize (cueChunk)
|
||||
+ chunkSize (listChunk)
|
||||
+ chunkSize (acidChunk)
|
||||
+ chunkSize (trckChunk)
|
||||
+ (8 + 28)); // (ds64 chunk)
|
||||
|
||||
riffChunkSize += (riffChunkSize & 1);
|
||||
|
|
@ -1112,6 +1193,8 @@ private:
|
|||
writeChunk (instChunk, chunkName ("inst"), 7);
|
||||
writeChunk (cueChunk, chunkName ("cue "));
|
||||
writeChunk (listChunk, chunkName ("LIST"));
|
||||
writeChunk (acidChunk, chunkName ("acid"));
|
||||
writeChunk (trckChunk, chunkName ("Trkn"));
|
||||
|
||||
writeChunkHeader (chunkName ("data"), isRF64 ? -1 : (int) (lengthInSamples * bytesPerFrame));
|
||||
|
||||
|
|
|
|||
|
|
@ -135,6 +135,9 @@ public:
|
|||
/** Metadata property name used when reading an ISRC code from an AXML chunk. */
|
||||
static const char* const ISRC;
|
||||
|
||||
/** Metadata property name used when reading a WAV file with a Tracktion chunk. */
|
||||
static const char* const tracktionLoopInfo;
|
||||
|
||||
//==============================================================================
|
||||
Array<int> getPossibleSampleRates() override;
|
||||
Array<int> getPossibleBitDepths() override;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue