Browse Source

Added better support for writing acid and Tracktion chunks in WavAudioFormat.

tags/2021-05-28
jules 11 years ago
parent
commit
b71447b057
3 changed files with 101 additions and 15 deletions
  1. +97
    -14
      modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp
  2. +3
    -0
      modules/juce_audio_formats/codecs/juce_WavAudioFormat.h
  3. +1
    -1
      modules/juce_audio_formats/format/juce_AudioFormatReader.cpp

+ 97
- 14
modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp View File

@@ -65,6 +65,7 @@ const char* const WavAudioFormat::acidNumerator = "acid numerator";
const char* const WavAudioFormat::acidTempo = "acid tempo"; const char* const WavAudioFormat::acidTempo = "acid tempo";
const char* const WavAudioFormat::ISRC = "ISRC"; const char* const WavAudioFormat::ISRC = "ISRC";
const char* const WavAudioFormat::tracktionLoopInfo = "tracktion loop info";
//============================================================================== //==============================================================================
namespace WavFileHelpers namespace WavFileHelpers
@@ -490,30 +491,100 @@ namespace WavFileHelpers
setBoolFlag (values, WavAudioFormat::acidizerFlag, 0x10); setBoolFlag (values, WavAudioFormat::acidizerFlag, 0x10);
if (flags & 0x02) // root note set 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; float reserved2;
int32 numBeats;
int16 meterDenominator;
int16 meterNumerator;
uint32 numBeats;
uint16 meterDenominator;
uint16 meterNumerator;
float tempo; float tempo;
} JUCE_PACKED; } 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 namespace AXMLChunk
{ {
@@ -816,6 +887,12 @@ public:
{ {
AcidChunk (*input, length).addToMetadata (metadataValues); 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()) else if (chunkEnd <= input->getPosition())
{ {
break; break;
@@ -919,6 +996,8 @@ public:
instChunk = InstChunk::createFrom (metadataValues); instChunk = InstChunk::createFrom (metadataValues);
cueChunk = CueChunk ::createFrom (metadataValues); cueChunk = CueChunk ::createFrom (metadataValues);
listChunk = ListChunk::createFrom (metadataValues); listChunk = ListChunk::createFrom (metadataValues);
acidChunk = AcidChunk::createFrom (metadataValues);
trckChunk = TracktionChunk::createFrom (metadataValues);
} }
headerPosition = out->getPosition(); headerPosition = out->getPosition();
@@ -981,7 +1060,7 @@ public:
} }
private: private:
MemoryBlock tempBlock, bwavChunk, axmlChunk, smplChunk, instChunk, cueChunk, listChunk;
MemoryBlock tempBlock, bwavChunk, axmlChunk, smplChunk, instChunk, cueChunk, listChunk, acidChunk, trckChunk;
uint64 lengthInSamples, bytesWritten; uint64 lengthInSamples, bytesWritten;
int64 headerPosition; int64 headerPosition;
bool writeFailed; bool writeFailed;
@@ -1033,6 +1112,8 @@ private:
+ chunkSize (instChunk) + chunkSize (instChunk)
+ chunkSize (cueChunk) + chunkSize (cueChunk)
+ chunkSize (listChunk) + chunkSize (listChunk)
+ chunkSize (acidChunk)
+ chunkSize (trckChunk)
+ (8 + 28)); // (ds64 chunk) + (8 + 28)); // (ds64 chunk)
riffChunkSize += (riffChunkSize & 1); riffChunkSize += (riffChunkSize & 1);
@@ -1112,6 +1193,8 @@ private:
writeChunk (instChunk, chunkName ("inst"), 7); writeChunk (instChunk, chunkName ("inst"), 7);
writeChunk (cueChunk, chunkName ("cue ")); writeChunk (cueChunk, chunkName ("cue "));
writeChunk (listChunk, chunkName ("LIST")); writeChunk (listChunk, chunkName ("LIST"));
writeChunk (acidChunk, chunkName ("acid"));
writeChunk (trckChunk, chunkName ("Trkn"));
writeChunkHeader (chunkName ("data"), isRF64 ? -1 : (int) (lengthInSamples * bytesPerFrame)); writeChunkHeader (chunkName ("data"), isRF64 ? -1 : (int) (lengthInSamples * bytesPerFrame));


+ 3
- 0
modules/juce_audio_formats/codecs/juce_WavAudioFormat.h View File

@@ -135,6 +135,9 @@ public:
/** Metadata property name used when reading an ISRC code from an AXML chunk. */ /** Metadata property name used when reading an ISRC code from an AXML chunk. */
static const char* const ISRC; 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> getPossibleSampleRates() override;
Array<int> getPossibleBitDepths() override; Array<int> getPossibleBitDepths() override;


+ 1
- 1
modules/juce_audio_formats/format/juce_AudioFormatReader.cpp View File

@@ -176,7 +176,7 @@ void AudioFormatReader::read (AudioSampleBuffer* buffer,
void AudioFormatReader::readMaxLevels (int64 startSampleInFile, int64 numSamples, void AudioFormatReader::readMaxLevels (int64 startSampleInFile, int64 numSamples,
Range<float>* const results, const int channelsToRead) Range<float>* const results, const int channelsToRead)
{ {
jassert (channelsToRead > 0 && channelsToRead <= numChannels);
jassert (channelsToRead > 0 && channelsToRead <= (int) numChannels);
if (numSamples <= 0) if (numSamples <= 0)
{ {


Loading…
Cancel
Save