1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-23 01:44:22 +00:00

Added support for the OGG sub-format inside a WAV file

This commit is contained in:
jules 2017-10-13 10:55:51 +01:00
parent d73f9bdd74
commit bb4160871c

View file

@ -166,11 +166,11 @@ namespace WavFileHelpers
struct BWAVChunk
{
char description [256];
char originator [32];
char originatorRef [32];
char originationDate [10];
char originationTime [8];
char description[256];
char originator[32];
char originatorRef[32];
char originationDate[10];
char originationTime[8];
uint32 timeRefLow;
uint32 timeRefHigh;
uint16 version;
@ -186,9 +186,9 @@ namespace WavFileHelpers
values.set (WavAudioFormat::bwavOriginationDate, String::fromUTF8 (originationDate, sizeof (originationDate)));
values.set (WavAudioFormat::bwavOriginationTime, String::fromUTF8 (originationTime, sizeof (originationTime)));
const uint32 timeLow = ByteOrder::swapIfBigEndian (timeRefLow);
const uint32 timeHigh = ByteOrder::swapIfBigEndian (timeRefHigh);
const int64 time = (((int64) timeHigh) << 32) + timeLow;
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,
@ -197,24 +197,24 @@ namespace WavFileHelpers
static MemoryBlock createFrom (const StringPairArray& values)
{
MemoryBlock data (roundUpSize (sizeof (BWAVChunk) + values [WavAudioFormat::bwavCodingHistory].getNumBytesAsUTF8()));
MemoryBlock data (roundUpSize (sizeof (BWAVChunk) + values[WavAudioFormat::bwavCodingHistory].getNumBytesAsUTF8()));
data.fillWith (0);
BWAVChunk* 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);
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);
const int64 time = values [WavAudioFormat::bwavTimeReference].getLargeIntValue();
auto time = 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);
values[WavAudioFormat::bwavCodingHistory].copyToUTF8 (b->codingHistory, 0x7fffffff);
if (b->description[0] != 0
|| b->originator[0] != 0
@ -321,7 +321,7 @@ namespace WavFileHelpers
static MemoryBlock createFrom (const StringPairArray& values)
{
MemoryBlock data;
const int numLoops = jmin (64, values.getValue ("NumSampleLoops", "0").getIntValue());
auto numLoops = jmin (64, values.getValue ("NumSampleLoops", "0").getIntValue());
data.setSize (roundUpSize (sizeof (SMPLChunk) + (size_t) (jmax (0, numLoops - 1)) * sizeof (SampleLoop)), true);
@ -528,7 +528,7 @@ namespace WavFileHelpers
auto text = values.getValue (prefix + "Text", prefix);
auto textLength = (int) text.getNumBytesAsUTF8() + 1; // include null terminator
int chunkLength = textLength + 20 + (textLength & 1);
auto chunkLength = textLength + 20 + (textLength & 1);
out.writeInt (chunkName ("ltxt"));
out.writeInt (chunkLength);
@ -673,9 +673,8 @@ namespace WavFileHelpers
{
while (input.getPosition() < chunkEnd)
{
const int infoType = input.readInt();
int64 infoLength = chunkEnd - input.getPosition();
auto infoType = input.readInt();
auto infoLength = chunkEnd - input.getPosition();
if (infoLength > 0)
{
@ -706,8 +705,8 @@ namespace WavFileHelpers
if (value.isEmpty())
return false;
const int valueLength = (int) value.getNumBytesAsUTF8() + 1;
const int chunkLength = valueLength + (valueLength & 1);
auto valueLength = (int) value.getNumBytesAsUTF8() + 1;
auto chunkLength = valueLength + (valueLength & 1);
out.writeInt (chunkName (paramName));
out.writeInt (chunkLength);
@ -831,7 +830,7 @@ namespace WavFileHelpers
static MemoryBlock createFrom (const StringPairArray& values)
{
MemoryOutputStream out;
const String s (values[WavAudioFormat::tracktionLoopInfo]);
auto s = values[WavAudioFormat::tracktionLoopInfo];
if (s.isNotEmpty())
{
@ -934,17 +933,16 @@ namespace WavFileHelpers
class WavAudioFormatReader : public AudioFormatReader
{
public:
WavAudioFormatReader (InputStream* const in)
: AudioFormatReader (in, wavFormatName)
WavAudioFormatReader (InputStream* in) : AudioFormatReader (in, wavFormatName)
{
using namespace WavFileHelpers;
uint64 len = 0;
uint64 end = 0;
uint64 len = 0, end = 0;
int cueNoteIndex = 0;
int cueLabelIndex = 0;
int cueRegionIndex = 0;
const int firstChunkType = input->readInt();
auto streamStartPos = input->getPosition();
auto firstChunkType = input->readInt();
if (firstChunkType == chunkName ("RF64"))
{
@ -967,12 +965,12 @@ public:
{
if (isRF64 && input->readInt() == chunkName ("ds64"))
{
const uint32 length = (uint32) input->readInt();
auto length = (uint32) input->readInt();
if (length < 28)
return;
const int64 chunkEnd = input->getPosition() + length + (length & 1);
auto chunkEnd = input->getPosition() + length + (length & 1);
len = (uint64) input->readInt64();
end = len + (uint64) startOfRIFFChunk;
dataLength = input->readInt64();
@ -981,9 +979,9 @@ public:
while ((uint64) input->getPosition() < end && ! input->isExhausted())
{
const int chunkType = input->readInt();
uint32 length = (uint32) input->readInt();
const int64 chunkEnd = input->getPosition() + length + (length & 1);
auto chunkType = input->readInt();
auto length = (uint32) input->readInt();
auto chunkEnd = input->getPosition() + length + (length & 1);
if (chunkType == chunkName ("fmt "))
{
@ -1009,7 +1007,7 @@ public:
{
usesFloatingPointData = true;
}
else if (format == 0xfffe /*WAVE_FORMAT_EXTENSIBLE*/)
else if (format == 0xfffe) // WAVE_FORMAT_EXTENSIBLE
{
if (length < 40) // too short
{
@ -1034,6 +1032,18 @@ public:
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;
@ -1187,7 +1197,7 @@ public:
while (numSamples > 0)
{
const int tempBufSize = 480 * 3 * 4; // (keep this a multiple of 3)
char tempBuffer [tempBufSize];
char tempBuffer[tempBufSize];
const int numThisTime = jmin (tempBufSize / bytesPerFrame, numSamples);
const int bytesRead = input->read (tempBuffer, numThisTime * bytesPerFrame);
@ -1267,6 +1277,8 @@ public:
int64 dataChunkStart = 0, dataLength = 0;
int bytesPerFrame = 0;
bool isRF64 = false;
bool isSubformatOggVorbis = false;
AudioChannelSet channelLayout;
private:
@ -1596,7 +1608,7 @@ public:
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] = Range<float>();
results[i] = {};
return;
}
@ -1630,17 +1642,13 @@ WavAudioFormat::~WavAudioFormat() {}
Array<int> WavAudioFormat::getPossibleSampleRates()
{
const int rates[] = { 8000, 11025, 12000, 16000, 22050, 32000, 44100,
48000, 88200, 96000, 176400, 192000, 352800, 384000 };
return Array<int> (rates, numElementsInArray (rates));
return { 8000, 11025, 12000, 16000, 22050, 32000, 44100,
48000, 88200, 96000, 176400, 192000, 352800, 384000 };
}
Array<int> WavAudioFormat::getPossibleBitDepths()
{
const int depths[] = { 8, 16, 24, 32 };
return Array<int> (depths, numElementsInArray (depths));
return { 8, 16, 24, 32 };
}
bool WavAudioFormat::canDoStereo() { return true; }
@ -1662,11 +1670,18 @@ bool WavAudioFormat::isChannelLayoutSupported (const AudioChannelSet& channelSet
return true;
}
AudioFormatReader* WavAudioFormat::createReaderFor (InputStream* sourceStream,
const bool deleteStreamIfOpeningFails)
AudioFormatReader* WavAudioFormat::createReaderFor (InputStream* sourceStream, bool deleteStreamIfOpeningFails)
{
ScopedPointer<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)
return r.release();
@ -1758,7 +1773,7 @@ bool WavAudioFormat::replaceMetadataInFile (const File& wavFile, const StringPai
if (bwavSize > 0)
{
MemoryBlock chunk (BWAVChunk::createFrom (newMetadata));
auto chunk = BWAVChunk::createFrom (newMetadata);
if (chunk.getSize() <= (size_t) bwavSize)
{
@ -1768,7 +1783,7 @@ bool WavAudioFormat::replaceMetadataInFile (const File& wavFile, const StringPai
{
FileOutputStream out (wavFile);
if (! out.failedToOpen())
if (out.openedOk())
{
out.setPosition (bwavPos);
out << chunk;
@ -1777,7 +1792,6 @@ bool WavAudioFormat::replaceMetadataInFile (const File& wavFile, const StringPai
}
jassert (wavFile.getSize() == oldSize);
return true;
}
}