Browse Source

Added RF64 support to WavAudioFormat. Extended some of the audio source classes to support 64-bit sample indices.

tags/2021-05-28
Julian Storer 14 years ago
parent
commit
8ade855f56
15 changed files with 556 additions and 344 deletions
  1. +258
    -155
      juce_amalgamated.cpp
  2. +19
    -16
      juce_amalgamated.h
  3. +0
    -4
      src/audio/audio_file_formats/juce_AiffAudioFormat.cpp
  4. +228
    -127
      src/audio/audio_file_formats/juce_WavAudioFormat.cpp
  5. +7
    -7
      src/audio/audio_sources/juce_AudioFormatReaderSource.cpp
  6. +4
    -4
      src/audio/audio_sources/juce_AudioFormatReaderSource.h
  7. +7
    -7
      src/audio/audio_sources/juce_AudioTransportSource.cpp
  8. +3
    -3
      src/audio/audio_sources/juce_AudioTransportSource.h
  9. +11
    -11
      src/audio/audio_sources/juce_BufferingAudioSource.cpp
  10. +5
    -5
      src/audio/audio_sources/juce_BufferingAudioSource.h
  11. +3
    -3
      src/audio/audio_sources/juce_PositionableAudioSource.h
  12. +1
    -1
      src/audio/dsp/juce_AudioSampleBuffer.cpp
  13. +1
    -1
      src/audio/dsp/juce_AudioSampleBuffer.h
  14. +6
    -0
      src/io/streams/juce_OutputStream.cpp
  15. +3
    -0
      src/io/streams/juce_OutputStream.h

+ 258
- 155
juce_amalgamated.cpp View File

@@ -6927,6 +6927,12 @@ void OutputStream::writeByte (char byte)
write (&byte, 1);
}

void OutputStream::writeRepeatedByte (uint8 byte, int numTimesToRepeat)
{
while (--numTimesToRepeat >= 0)
writeByte (byte);
}

void OutputStream::writeShort (short value)
{
const unsigned short v = ByteOrder::swapIfBigEndian ((unsigned short) value);
@@ -20729,10 +20735,6 @@ public:
}
}

~AiffAudioFormatReader()
{
}

bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer,
int64 startSampleInFile, int numSamples)
{
@@ -23091,6 +23093,9 @@ const StringPairArray WavAudioFormat::createBWAVMetadata (const String& descript
return m;
}

namespace WavFileHelpers
{

#if JUCE_MSVC
#pragma pack (push, 1)
#define PACKED
@@ -23265,12 +23270,26 @@ struct ExtensibleWavSubFormat
uint8 data4[8];
} PACKED;

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'
} PACKED;

#if JUCE_MSVC
#pragma pack (pop)
#endif

#undef PACKED

inline int chunkName (const char* const name) { return (int) ByteOrder::littleEndianInt (name); }
}

class WavAudioFormatReader : public AudioFormatReader
{
public:
@@ -23279,109 +23298,146 @@ public:
: AudioFormatReader (in, TRANS (wavFormatName)),
bwavChunkStart (0),
bwavSize (0),
dataLength (0)
dataLength (0),
isRF64 (false)
{
if (input->readInt() == chunkName ("RIFF"))
using namespace WavFileHelpers;
uint64 len = 0;
int64 end = 0;
bool hasGotType = false;
bool hasGotData = false;

const int firstChunkType = input->readInt();

if (firstChunkType == chunkName ("RF64"))
{
const uint32 len = (uint32) input->readInt();
const int64 end = input->getPosition() + len;
bool hasGotType = false;
bool hasGotData = false;
input->skipNextBytes (4); // size is -1 for RF64
isRF64 = true;
}
else if (firstChunkType == chunkName ("RIFF"))
{
len = (uint64) input->readInt();
end = input->getPosition() + len;
}
else
{
return;
}

if (input->readInt() == chunkName ("WAVE"))
const int64 startOfRIFFChunk = input->getPosition();

if (input->readInt() == chunkName ("WAVE"))
{
if (isRF64 && input->readInt() == chunkName ("ds64"))
{
while (input->getPosition() < end
&& ! input->isExhausted())
uint32 length = (uint32) input->readInt();

if (length < 28)
{
return;
}
else
{
const int chunkType = input->readInt();
uint32 length = (uint32) input->readInt();
const int64 chunkEnd = input->getPosition() + length + (length & 1);
len = input->readInt64();
end = startOfRIFFChunk + len;
dataLength = input->readInt64();
input->setPosition (chunkEnd);
}
}

if (chunkType == chunkName ("fmt "))
{
// read the format chunk
const unsigned short format = input->readShort();
const short numChans = input->readShort();
sampleRate = input->readInt();
const int bytesPerSec = input->readInt();
while (input->getPosition() < end && ! input->isExhausted())
{
const int chunkType = input->readInt();
uint32 length = (uint32) input->readInt();
const int64 chunkEnd = input->getPosition() + length + (length & 1);

numChannels = numChans;
bytesPerFrame = bytesPerSec / (int)sampleRate;
bitsPerSample = 8 * bytesPerFrame / numChans;
if (chunkType == chunkName ("fmt "))
{
// read the format chunk
const unsigned short format = input->readShort();
const short numChans = input->readShort();
sampleRate = input->readInt();
const int bytesPerSec = input->readInt();

numChannels = numChans;
bytesPerFrame = bytesPerSec / (int)sampleRate;
bitsPerSample = 8 * bytesPerFrame / numChans;

if (format == 3)
if (format == 3)
{
usesFloatingPointData = true;
}
else if (format == 0xfffe /*WAVE_FORMAT_EXTENSIBLE*/)
{
if (length < 40) // too short
{
usesFloatingPointData = true;
bytesPerFrame = 0;
}
else if (format == 0xfffe /*WAVE_FORMAT_EXTENSIBLE*/)
else
{
if (length < 40) // too short
{
bytesPerFrame = 0;
}
else
{
input->skipNextBytes (12); // skip over blockAlign, bitsPerSample and speakerPosition mask
ExtensibleWavSubFormat subFormat;
subFormat.data1 = input->readInt();
subFormat.data2 = input->readShort();
subFormat.data3 = input->readShort();
input->read (subFormat.data4, sizeof (subFormat.data4));
input->skipNextBytes (12); // skip over blockAlign, bitsPerSample and speakerPosition mask
ExtensibleWavSubFormat subFormat;
subFormat.data1 = input->readInt();
subFormat.data2 = input->readShort();
subFormat.data3 = input->readShort();
input->read (subFormat.data4, sizeof (subFormat.data4));

const ExtensibleWavSubFormat pcmFormat
= { 0x00000001, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
const ExtensibleWavSubFormat pcmFormat
= { 0x00000001, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };

if (memcmp (&subFormat, &pcmFormat, sizeof (subFormat)) != 0)
{
const ExtensibleWavSubFormat ambisonicFormat
= { 0x00000001, 0x0721, 0x11d3, { 0x86, 0x44, 0xC8, 0xC1, 0xCA, 0x00, 0x00, 0x00 } };
if (memcmp (&subFormat, &pcmFormat, sizeof (subFormat)) != 0)
{
const ExtensibleWavSubFormat ambisonicFormat
= { 0x00000001, 0x0721, 0x11d3, { 0x86, 0x44, 0xC8, 0xC1, 0xCA, 0x00, 0x00, 0x00 } };

if (memcmp (&subFormat, &ambisonicFormat, sizeof (subFormat)) != 0)
bytesPerFrame = 0;
}
if (memcmp (&subFormat, &ambisonicFormat, sizeof (subFormat)) != 0)
bytesPerFrame = 0;
}
}
else if (format != 1)
{
bytesPerFrame = 0;
}

hasGotType = true;
}
else if (chunkType == chunkName ("data"))
else if (format != 1)
{
// get the data chunk's position
bytesPerFrame = 0;
}

hasGotType = true;
}
else if (chunkType == chunkName ("data"))
{
// get the data chunk's position
if (! isRF64) // data size is expected to be -1, actual data size is in ds64 chunk
dataLength = length;
dataChunkStart = input->getPosition();
lengthInSamples = (bytesPerFrame > 0) ? (dataLength / bytesPerFrame) : 0;

hasGotData = true;
}
else if (chunkType == chunkName ("bext"))
{
bwavChunkStart = input->getPosition();
bwavSize = length;

// Broadcast-wav extension chunk..
HeapBlock <BWAVChunk> bwav;
bwav.calloc (jmax ((size_t) length + 1, sizeof (BWAVChunk)), 1);
input->read (bwav, length);
bwav->copyTo (metadataValues);
}
else if (chunkType == chunkName ("smpl"))
{
HeapBlock <SMPLChunk> smpl;
smpl.calloc (jmax ((size_t) length + 1, sizeof (SMPLChunk)), 1);
input->read (smpl, length);
smpl->copyTo (metadataValues, length);
}
else if (chunkEnd <= input->getPosition())
{
break;
}
dataChunkStart = input->getPosition();
lengthInSamples = (bytesPerFrame > 0) ? (dataLength / bytesPerFrame) : 0;

input->setPosition (chunkEnd);
hasGotData = true;
}
else if (chunkType == chunkName ("bext"))
{
bwavChunkStart = input->getPosition();
bwavSize = length;

// Broadcast-wav extension chunk..
HeapBlock <BWAVChunk> bwav;
bwav.calloc (jmax ((size_t) length + 1, sizeof (BWAVChunk)), 1);
input->read (bwav, length);
bwav->copyTo (metadataValues);
}
else if (chunkType == chunkName ("smpl"))
{
HeapBlock <SMPLChunk> smpl;
smpl.calloc (jmax ((size_t) length + 1, sizeof (SMPLChunk)), 1);
input->read (smpl, length);
smpl->copyTo (metadataValues, length);
}
else if (chunkEnd <= input->getPosition())
{
break;
}

input->setPosition (chunkEnd);
}
}
}
@@ -23443,8 +23499,7 @@ private:
ScopedPointer<AudioData::Converter> converter;
int bytesPerFrame;
int64 dataChunkStart, dataLength;

static inline int chunkName (const char* const name) { return (int) ByteOrder::littleEndianInt (name); }
bool isRF64;

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WavAudioFormatReader);
};
@@ -23453,20 +23508,17 @@ class WavAudioFormatWriter : public AudioFormatWriter
{
public:

WavAudioFormatWriter (OutputStream* const out,
const double sampleRate_,
const unsigned int numChannels_,
const int bits,
WavAudioFormatWriter (OutputStream* const out, const double sampleRate_,
const unsigned int numChannels_, const int bits,
const StringPairArray& metadataValues)
: AudioFormatWriter (out,
TRANS (wavFormatName),
sampleRate_,
numChannels_,
bits),
: AudioFormatWriter (out, TRANS (wavFormatName), sampleRate_, numChannels_, bits),
lengthInSamples (0),
bytesWritten (0),
writeFailed (false)
writeFailed (false),
isRF64 (false)
{
using namespace WavFileHelpers;

if (metadataValues.size() > 0)
{
bwavChunk = BWAVChunk::createFrom (metadataValues);
@@ -23479,6 +23531,12 @@ public:

~WavAudioFormatWriter()
{
if ((bytesWritten & 1) != 0) // pad to an even length
{
++bytesWritten;
output->writeByte (0);
}

writeHeader();
}

@@ -23501,8 +23559,7 @@ public:
default: jassertfalse; break;
}

if (bytesWritten + bytes >= (uint32) 0xfff00000
|| ! output->write (tempBlock.getData(), bytes))
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
@@ -23523,14 +23580,27 @@ public:
private:
ScopedPointer<AudioData::Converter> converter;
MemoryBlock tempBlock, bwavChunk, smplChunk;
uint32 lengthInSamples, bytesWritten;
uint64 lengthInSamples, bytesWritten;
int64 headerPosition;
bool writeFailed;
bool writeFailed, isRF64;

static inline int chunkName (const char* const name) { return (int) ByteOrder::littleEndianInt (name); }
static int getChannelMask (const int numChannels) throw()
{
switch (numChannels)
{
case 1: return 0;
case 2: return 1 + 2; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT
case 5: return 1 + 2 + 4 + 16 + 32; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT
case 6: return 1 + 2 + 4 + 8 + 16 + 32; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT
default: break;
}

return 0;
}

void writeHeader()
{
using namespace WavFileHelpers;
const bool seekedOk = output->setPosition (headerPosition);
(void) seekedOk;

@@ -23539,21 +23609,62 @@ private:
jassert (seekedOk);

const int bytesPerFrame = numChannels * bitsPerSample / 8;
output->writeInt (chunkName ("RIFF"));
output->writeInt ((int) (lengthInSamples * bytesPerFrame
+ ((bwavChunk.getSize() > 0) ? (44 + bwavChunk.getSize()) : 36)
+ (smplChunk.getSize() > 0 ? smplChunk.getSize() + 8 : 0)));
int64 audioDataSize = bytesPerFrame * lengthInSamples;

int64 riffChunkSize = 4 /* 'WAVE' */ + 8 + 40 /* WAVEFORMATEX */
+ 8 + audioDataSize + (audioDataSize & 1)
+ (bwavChunk.getSize() > 0 ? (8 + bwavChunk.getSize()) : 0)
+ (smplChunk.getSize() > 0 ? (8 + smplChunk.getSize()) : 0)
+ (8 + 28); // (JUNK chunk)

riffChunkSize += (riffChunkSize & 0x1);
isRF64 = (riffChunkSize > 0xffffffff);

output->writeInt (chunkName (isRF64 ? "RF64" : "RIFF"));
output->writeInt (isRF64 ? -1 : (int) riffChunkSize);
output->writeInt (chunkName ("WAVE"));

if (! isRF64)
{
// write Junk chunk
output->writeInt (chunkName ("JUNK"));
output->writeInt (28);
output->writeRepeatedByte (0, 28);
}
else
{
// write ds64 chunk
output->writeInt (chunkName ("ds64"));
output->writeInt (28); // chunk size for uncompressed data (no table)
output->writeInt64 (riffChunkSize);
output->writeInt64 (audioDataSize);
output->writeRepeatedByte (0, 12);
}

output->writeInt (chunkName ("fmt "));
output->writeInt (16);
output->writeShort ((bitsPerSample < 32) ? (short) 1 /*WAVE_FORMAT_PCM*/
: (short) 3 /*WAVE_FORMAT_IEEE_FLOAT*/);
output->writeInt (40); // WAVEFORMATEX chunk size
output->writeShort ((short) (uint16) 0xfffe); // WAVE_FORMAT_EXTENSIBLE
output->writeShort ((short) numChannels);
output->writeInt ((int) sampleRate);
output->writeInt (bytesPerFrame * (int) sampleRate);
output->writeShort ((short) bytesPerFrame);
output->writeShort ((short) bitsPerSample);
output->writeInt ((int) (bytesPerFrame * sampleRate)); // nAvgBytesPerSec
output->writeShort ((short) bytesPerFrame); // nBlockAlign
output->writeShort ((short) bitsPerSample); // wBitsPerSample
output->writeShort (22); // cbSize (size of the extension)
output->writeShort ((short) bitsPerSample); // wValidBitsPerSample
output->writeInt (getChannelMask (numChannels));

const ExtensibleWavSubFormat pcmFormat
= { 0x00000001, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };

const ExtensibleWavSubFormat IEEEFloatFormat
= { 0x00000003, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };

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));

if (bwavChunk.getSize() > 0)
{
@@ -23570,7 +23681,7 @@ private:
}

output->writeInt (chunkName ("data"));
output->writeInt (lengthInSamples * bytesPerFrame);
output->writeInt (isRF64 ? -1 : (int) (lengthInSamples * bytesPerFrame));

usesFloatingPointData = (bitsPerSample == 32);
}
@@ -23616,28 +23727,19 @@ AudioFormatReader* WavAudioFormat::createReaderFor (InputStream* sourceStream,
return 0;
}

AudioFormatWriter* WavAudioFormat::createWriterFor (OutputStream* out,
double sampleRate,
unsigned int numChannels,
int bitsPerSample,
const StringPairArray& metadataValues,
int /*qualityOptionIndex*/)
AudioFormatWriter* WavAudioFormat::createWriterFor (OutputStream* out, double sampleRate,
unsigned int numChannels, int bitsPerSample,
const StringPairArray& metadataValues, int /*qualityOptionIndex*/)
{
if (getPossibleBitDepths().contains (bitsPerSample))
{
return new WavAudioFormatWriter (out,
sampleRate,
numChannels,
bitsPerSample,
metadataValues);
}
return new WavAudioFormatWriter (out, sampleRate, numChannels, bitsPerSample, metadataValues);

return 0;
}

namespace
namespace WavFileHelpers
{
bool juce_slowCopyOfWavFileWithNewMetadata (const File& file, const StringPairArray& metadata)
bool slowCopyWavFileWithNewMetadata (const File& file, const StringPairArray& metadata)
{
TemporaryFile tempFile (file);

@@ -23673,7 +23775,8 @@ namespace

bool WavAudioFormat::replaceMetadataInFile (const File& wavFile, const StringPairArray& newMetadata)
{
ScopedPointer <WavAudioFormatReader> reader ((WavAudioFormatReader*) createReaderFor (wavFile.createInputStream(), true));
using namespace WavFileHelpers;
ScopedPointer <WavAudioFormatReader> reader (static_cast <WavAudioFormatReader*> (createReaderFor (wavFile.createInputStream(), true)));

if (reader != 0)
{
@@ -23704,7 +23807,7 @@ bool WavAudioFormat::replaceMetadataInFile (const File& wavFile, const StringPai
}
}

return juce_slowCopyOfWavFileWithNewMetadata (wavFile, newMetadata);
return slowCopyWavFileWithNewMetadata (wavFile, newMetadata);
}

END_JUCE_NAMESPACE
@@ -23773,7 +23876,7 @@ AudioFormatReaderSource::~AudioFormatReaderSource()
delete reader;
}

void AudioFormatReaderSource::setNextReadPosition (int newPosition)
void AudioFormatReaderSource::setNextReadPosition (int64 newPosition)
{
nextPlayPos = newPosition;
}
@@ -23783,15 +23886,15 @@ void AudioFormatReaderSource::setLooping (bool shouldLoop)
looping = shouldLoop;
}

int AudioFormatReaderSource::getNextReadPosition() const
int64 AudioFormatReaderSource::getNextReadPosition() const
{
return (looping) ? (nextPlayPos % (int) reader->lengthInSamples)
: nextPlayPos;
return looping ? nextPlayPos % reader->lengthInSamples
: nextPlayPos;
}

int AudioFormatReaderSource::getTotalLength() const
int64 AudioFormatReaderSource::getTotalLength() const
{
return (int) reader->lengthInSamples;
return reader->lengthInSamples;
}

void AudioFormatReaderSource::prepareToPlay (int /*samplesPerBlockExpected*/,
@@ -23807,7 +23910,7 @@ void AudioFormatReaderSource::getNextAudioBlock (const AudioSourceChannelInfo& i
{
if (info.numSamples > 0)
{
const int start = nextPlayPos;
const int64 start = nextPlayPos;

if (looping)
{
@@ -24152,7 +24255,7 @@ void AudioTransportSource::stop()
void AudioTransportSource::setPosition (double newPosition)
{
if (sampleRate > 0.0)
setNextReadPosition (roundToInt (newPosition * sampleRate));
setNextReadPosition ((int64) (newPosition * sampleRate));
}

double AudioTransportSource::getCurrentPosition() const
@@ -24168,30 +24271,30 @@ double AudioTransportSource::getLengthInSeconds() const
return getTotalLength() / sampleRate;
}

void AudioTransportSource::setNextReadPosition (int newPosition)
void AudioTransportSource::setNextReadPosition (int64 newPosition)
{
if (positionableSource != 0)
{
if (sampleRate > 0 && sourceSampleRate > 0)
newPosition = roundToInt (newPosition * sourceSampleRate / sampleRate);
newPosition = (int64) (newPosition * sourceSampleRate / sampleRate);

positionableSource->setNextReadPosition (newPosition);
}
}

int AudioTransportSource::getNextReadPosition() const
int64 AudioTransportSource::getNextReadPosition() const
{
if (positionableSource != 0)
{
const double ratio = (sampleRate > 0 && sourceSampleRate > 0) ? sampleRate / sourceSampleRate : 1.0;

return roundToInt (positionableSource->getNextReadPosition() * ratio);
return (int64) (positionableSource->getNextReadPosition() * ratio);
}

return 0;
}

int AudioTransportSource::getTotalLength() const
int64 AudioTransportSource::getTotalLength() const
{
const ScopedLock sl (callbackLock);

@@ -24199,7 +24302,7 @@ int AudioTransportSource::getTotalLength() const
{
const double ratio = (sampleRate > 0 && sourceSampleRate > 0) ? sampleRate / sourceSampleRate : 1.0;

return roundToInt (positionableSource->getTotalLength() * ratio);
return (int64) (positionableSource->getTotalLength() * ratio);
}

return 0;
@@ -24446,8 +24549,8 @@ void BufferingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info
{
const ScopedLock sl (bufferStartPosLock);

const int validStart = jlimit (bufferValidStart, bufferValidEnd, nextPlayPos) - nextPlayPos;
const int validEnd = jlimit (bufferValidStart, bufferValidEnd, nextPlayPos + info.numSamples) - nextPlayPos;
const int validStart = (int) (jlimit (bufferValidStart, bufferValidEnd, nextPlayPos) - nextPlayPos);
const int validEnd = (int) (jlimit (bufferValidStart, bufferValidEnd, nextPlayPos + info.numSamples) - nextPlayPos);

if (validStart == validEnd)
{
@@ -24506,14 +24609,14 @@ void BufferingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info
thread->notify();
}

int BufferingAudioSource::getNextReadPosition() const
int64 BufferingAudioSource::getNextReadPosition() const
{
return (source->isLooping() && nextPlayPos > 0)
? nextPlayPos % source->getTotalLength()
: nextPlayPos;
}

void BufferingAudioSource::setNextReadPosition (int newPosition)
void BufferingAudioSource::setNextReadPosition (int64 newPosition)
{
const ScopedLock sl (bufferStartPosLock);

@@ -24527,7 +24630,7 @@ void BufferingAudioSource::setNextReadPosition (int newPosition)

bool BufferingAudioSource::readNextBufferChunk()
{
int newBVS, newBVE, sectionToReadStart, sectionToReadEnd;
int64 newBVS, newBVE, sectionToReadStart, sectionToReadEnd;

{
const ScopedLock sl (bufferStartPosLock);
@@ -24539,7 +24642,7 @@ bool BufferingAudioSource::readNextBufferChunk()
bufferValidEnd = 0;
}

newBVS = jmax (0, nextPlayPos);
newBVS = jmax ((int64) 0, nextPlayPos);
newBVE = newBVS + buffer.getNumSamples() - 4;
sectionToReadStart = 0;
sectionToReadEnd = 0;
@@ -24556,8 +24659,8 @@ bool BufferingAudioSource::readNextBufferChunk()
bufferValidStart = 0;
bufferValidEnd = 0;
}
else if (abs (newBVS - bufferValidStart) > 512
|| abs (newBVE - bufferValidEnd) > 512)
else if (std::abs ((int) (newBVS - bufferValidStart)) > 512
|| std::abs ((int) (newBVE - bufferValidEnd)) > 512)
{
newBVE = jmin (newBVE, bufferValidEnd + maxChunkSize);

@@ -24577,7 +24680,7 @@ bool BufferingAudioSource::readNextBufferChunk()
if (bufferIndexStart < bufferIndexEnd)
{
readBufferSection (sectionToReadStart,
sectionToReadEnd - sectionToReadStart,
(int) (sectionToReadEnd - sectionToReadStart),
bufferIndexStart);
}
else
@@ -24589,7 +24692,7 @@ bool BufferingAudioSource::readNextBufferChunk()
bufferIndexStart);

readBufferSection (sectionToReadStart + initialSize,
(sectionToReadEnd - sectionToReadStart) - initialSize,
(int) (sectionToReadEnd - sectionToReadStart) - initialSize,
0);
}

@@ -24606,7 +24709,7 @@ bool BufferingAudioSource::readNextBufferChunk()
}
}

void BufferingAudioSource::readBufferSection (int start, int length, int bufferOffset)
void BufferingAudioSource::readBufferSection (const int64 start, const int length, const int bufferOffset)
{
if (source->getNextReadPosition() != start)
source->setNextReadPosition (start);
@@ -27565,7 +27668,7 @@ float AudioSampleBuffer::getRMSLevel (const int channel,
void AudioSampleBuffer::readFromAudioReader (AudioFormatReader* reader,
const int startSample,
const int numSamples,
const int readerStartSample,
const int64 readerStartSample,
const bool useLeftChan,
const bool useRightChan)
{


+ 19
- 16
juce_amalgamated.h View File

@@ -5962,6 +5962,9 @@ public:
*/
virtual void writeDoubleBigEndian (double value);

/** Writes a byte to the output stream a given number of times. */
virtual void writeRepeatedByte (uint8 byte, int numTimesToRepeat);

/** Writes a condensed binary encoding of a 32-bit integer.

If you're storing a lot of integers which are unlikely to have very large values,
@@ -32536,7 +32539,7 @@ public:
void readFromAudioReader (AudioFormatReader* reader,
int startSample,
int numSamples,
int readerStartSample,
int64 readerStartSample,
bool useReaderLeftChan,
bool useReaderRightChan);

@@ -34174,16 +34177,16 @@ public:
Note that this may be called on a different thread to getNextAudioBlock(),
so the subclass should make sure it's synchronised.
*/
virtual void setNextReadPosition (int newPosition) = 0;
virtual void setNextReadPosition (int64 newPosition) = 0;

/** Returns the position from which the next block will be returned.

@see setNextReadPosition
*/
virtual int getNextReadPosition() const = 0;
virtual int64 getNextReadPosition() const = 0;

/** Returns the total length of the stream (in samples). */
virtual int getTotalLength() const = 0;
virtual int64 getTotalLength() const = 0;

/** Returns true if this source is actually playing in a loop. */
virtual bool isLooping() const = 0;
@@ -34242,20 +34245,20 @@ public:
void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill);

/** Implements the PositionableAudioSource method. */
void setNextReadPosition (int newPosition);
void setNextReadPosition (int64 newPosition);

/** Implements the PositionableAudioSource method. */
int getNextReadPosition() const;
int64 getNextReadPosition() const;

/** Implements the PositionableAudioSource method. */
int getTotalLength() const;
int64 getTotalLength() const;

private:

AudioFormatReader* reader;
bool deleteReader;

int volatile nextPlayPos;
int64 volatile nextPlayPos;
bool volatile looping;

void readBufferSection (int start, int length, AudioSampleBuffer& buffer, int startSample);
@@ -34707,13 +34710,13 @@ public:
void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill);

/** Implements the PositionableAudioSource method. */
void setNextReadPosition (int newPosition);
void setNextReadPosition (int64 newPosition);

/** Implements the PositionableAudioSource method. */
int getNextReadPosition() const;
int64 getNextReadPosition() const;

/** Implements the PositionableAudioSource method. */
int getTotalLength() const { return source->getTotalLength(); }
int64 getTotalLength() const { return source->getTotalLength(); }

/** Implements the PositionableAudioSource method. */
bool isLooping() const { return source->isLooping(); }
@@ -34725,13 +34728,13 @@ private:
int numberOfSamplesToBuffer;
AudioSampleBuffer buffer;
CriticalSection bufferStartPosLock;
int volatile bufferValidStart, bufferValidEnd, nextPlayPos;
int64 volatile bufferValidStart, bufferValidEnd, nextPlayPos;
bool wasSourceLooping;
double volatile sampleRate;

friend class SharedBufferingAudioSourceThread;
bool readNextBufferChunk();
void readBufferSection (int start, int length, int bufferOffset);
void readBufferSection (int64 start, int length, int bufferOffset);

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BufferingAudioSource);
};
@@ -34928,13 +34931,13 @@ public:
void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill);

/** Implements the PositionableAudioSource method. */
void setNextReadPosition (int newPosition);
void setNextReadPosition (int64 newPosition);

/** Implements the PositionableAudioSource method. */
int getNextReadPosition() const;
int64 getNextReadPosition() const;

/** Implements the PositionableAudioSource method. */
int getTotalLength() const;
int64 getTotalLength() const;

/** Implements the PositionableAudioSource method. */
bool isLooping() const;


+ 0
- 4
src/audio/audio_file_formats/juce_AiffAudioFormat.cpp View File

@@ -144,10 +144,6 @@ public:
}
}
~AiffAudioFormatReader()
{
}
//==============================================================================
bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer,
int64 startSampleInFile, int numSamples)


+ 228
- 127
src/audio/audio_file_formats/juce_WavAudioFormat.cpp View File

@@ -69,6 +69,9 @@ const StringPairArray WavAudioFormat::createBWAVMetadata (const String& descript
//==============================================================================
namespace WavFileHelpers
{
#if JUCE_MSVC
#pragma pack (push, 1)
#define PACKED
@@ -246,6 +249,17 @@ struct ExtensibleWavSubFormat
uint8 data4[8];
} PACKED;
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'
} PACKED;
#if JUCE_MSVC
#pragma pack (pop)
@@ -253,6 +267,9 @@ struct ExtensibleWavSubFormat
#undef PACKED
inline int chunkName (const char* const name) { return (int) ByteOrder::littleEndianInt (name); }
}
//==============================================================================
class WavAudioFormatReader : public AudioFormatReader
@@ -263,109 +280,146 @@ public:
: AudioFormatReader (in, TRANS (wavFormatName)),
bwavChunkStart (0),
bwavSize (0),
dataLength (0)
dataLength (0),
isRF64 (false)
{
if (input->readInt() == chunkName ("RIFF"))
using namespace WavFileHelpers;
uint64 len = 0;
int64 end = 0;
bool hasGotType = false;
bool hasGotData = false;
const int firstChunkType = input->readInt();
if (firstChunkType == chunkName ("RF64"))
{
input->skipNextBytes (4); // size is -1 for RF64
isRF64 = true;
}
else if (firstChunkType == chunkName ("RIFF"))
{
const uint32 len = (uint32) input->readInt();
const int64 end = input->getPosition() + len;
bool hasGotType = false;
bool hasGotData = false;
len = (uint64) input->readInt();
end = input->getPosition() + len;
}
else
{
return;
}
const int64 startOfRIFFChunk = input->getPosition();
if (input->readInt() == chunkName ("WAVE"))
if (input->readInt() == chunkName ("WAVE"))
{
if (isRF64 && input->readInt() == chunkName ("ds64"))
{
while (input->getPosition() < end
&& ! input->isExhausted())
uint32 length = (uint32) input->readInt();
if (length < 28)
{
return;
}
else
{
const int chunkType = input->readInt();
uint32 length = (uint32) input->readInt();
const int64 chunkEnd = input->getPosition() + length + (length & 1);
len = input->readInt64();
end = startOfRIFFChunk + len;
dataLength = input->readInt64();
input->setPosition (chunkEnd);
}
}
if (chunkType == chunkName ("fmt "))
{
// read the format chunk
const unsigned short format = input->readShort();
const short numChans = input->readShort();
sampleRate = input->readInt();
const int bytesPerSec = input->readInt();
while (input->getPosition() < end && ! input->isExhausted())
{
const int chunkType = input->readInt();
uint32 length = (uint32) input->readInt();
const int64 chunkEnd = input->getPosition() + length + (length & 1);
if (chunkType == chunkName ("fmt "))
{
// read the format chunk
const unsigned short format = input->readShort();
const short numChans = input->readShort();
sampleRate = input->readInt();
const int bytesPerSec = input->readInt();
numChannels = numChans;
bytesPerFrame = bytesPerSec / (int)sampleRate;
bitsPerSample = 8 * bytesPerFrame / numChans;
numChannels = numChans;
bytesPerFrame = bytesPerSec / (int)sampleRate;
bitsPerSample = 8 * bytesPerFrame / numChans;
if (format == 3)
if (format == 3)
{
usesFloatingPointData = true;
}
else if (format == 0xfffe /*WAVE_FORMAT_EXTENSIBLE*/)
{
if (length < 40) // too short
{
usesFloatingPointData = true;
bytesPerFrame = 0;
}
else if (format == 0xfffe /*WAVE_FORMAT_EXTENSIBLE*/)
else
{
if (length < 40) // too short
{
bytesPerFrame = 0;
}
else
input->skipNextBytes (12); // skip over blockAlign, bitsPerSample and speakerPosition mask
ExtensibleWavSubFormat subFormat;
subFormat.data1 = input->readInt();
subFormat.data2 = input->readShort();
subFormat.data3 = input->readShort();
input->read (subFormat.data4, sizeof (subFormat.data4));
const ExtensibleWavSubFormat pcmFormat
= { 0x00000001, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
if (memcmp (&subFormat, &pcmFormat, sizeof (subFormat)) != 0)
{
input->skipNextBytes (12); // skip over blockAlign, bitsPerSample and speakerPosition mask
ExtensibleWavSubFormat subFormat;
subFormat.data1 = input->readInt();
subFormat.data2 = input->readShort();
subFormat.data3 = input->readShort();
input->read (subFormat.data4, sizeof (subFormat.data4));
const ExtensibleWavSubFormat pcmFormat
= { 0x00000001, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
if (memcmp (&subFormat, &pcmFormat, sizeof (subFormat)) != 0)
{
const ExtensibleWavSubFormat ambisonicFormat
= { 0x00000001, 0x0721, 0x11d3, { 0x86, 0x44, 0xC8, 0xC1, 0xCA, 0x00, 0x00, 0x00 } };
if (memcmp (&subFormat, &ambisonicFormat, sizeof (subFormat)) != 0)
bytesPerFrame = 0;
}
const ExtensibleWavSubFormat ambisonicFormat
= { 0x00000001, 0x0721, 0x11d3, { 0x86, 0x44, 0xC8, 0xC1, 0xCA, 0x00, 0x00, 0x00 } };
if (memcmp (&subFormat, &ambisonicFormat, sizeof (subFormat)) != 0)
bytesPerFrame = 0;
}
}
else if (format != 1)
{
bytesPerFrame = 0;
}
hasGotType = true;
}
else if (chunkType == chunkName ("data"))
else if (format != 1)
{
// get the data chunk's position
bytesPerFrame = 0;
}
hasGotType = true;
}
else if (chunkType == chunkName ("data"))
{
// get the data chunk's position
if (! isRF64) // data size is expected to be -1, actual data size is in ds64 chunk
dataLength = length;
dataChunkStart = input->getPosition();
lengthInSamples = (bytesPerFrame > 0) ? (dataLength / bytesPerFrame) : 0;
hasGotData = true;
}
else if (chunkType == chunkName ("bext"))
{
bwavChunkStart = input->getPosition();
bwavSize = length;
// Broadcast-wav extension chunk..
HeapBlock <BWAVChunk> bwav;
bwav.calloc (jmax ((size_t) length + 1, sizeof (BWAVChunk)), 1);
input->read (bwav, length);
bwav->copyTo (metadataValues);
}
else if (chunkType == chunkName ("smpl"))
{
HeapBlock <SMPLChunk> smpl;
smpl.calloc (jmax ((size_t) length + 1, sizeof (SMPLChunk)), 1);
input->read (smpl, length);
smpl->copyTo (metadataValues, length);
}
else if (chunkEnd <= input->getPosition())
{
break;
}
dataChunkStart = input->getPosition();
lengthInSamples = (bytesPerFrame > 0) ? (dataLength / bytesPerFrame) : 0;
input->setPosition (chunkEnd);
hasGotData = true;
}
else if (chunkType == chunkName ("bext"))
{
bwavChunkStart = input->getPosition();
bwavSize = length;
// Broadcast-wav extension chunk..
HeapBlock <BWAVChunk> bwav;
bwav.calloc (jmax ((size_t) length + 1, sizeof (BWAVChunk)), 1);
input->read (bwav, length);
bwav->copyTo (metadataValues);
}
else if (chunkType == chunkName ("smpl"))
{
HeapBlock <SMPLChunk> smpl;
smpl.calloc (jmax ((size_t) length + 1, sizeof (SMPLChunk)), 1);
input->read (smpl, length);
smpl->copyTo (metadataValues, length);
}
else if (chunkEnd <= input->getPosition())
{
break;
}
input->setPosition (chunkEnd);
}
}
}
@@ -428,8 +482,7 @@ private:
ScopedPointer<AudioData::Converter> converter;
int bytesPerFrame;
int64 dataChunkStart, dataLength;
static inline int chunkName (const char* const name) { return (int) ByteOrder::littleEndianInt (name); }
bool isRF64;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WavAudioFormatReader);
};
@@ -439,20 +492,17 @@ class WavAudioFormatWriter : public AudioFormatWriter
{
public:
//==============================================================================
WavAudioFormatWriter (OutputStream* const out,
const double sampleRate_,
const unsigned int numChannels_,
const int bits,
WavAudioFormatWriter (OutputStream* const out, const double sampleRate_,
const unsigned int numChannels_, const int bits,
const StringPairArray& metadataValues)
: AudioFormatWriter (out,
TRANS (wavFormatName),
sampleRate_,
numChannels_,
bits),
: AudioFormatWriter (out, TRANS (wavFormatName), sampleRate_, numChannels_, bits),
lengthInSamples (0),
bytesWritten (0),
writeFailed (false)
writeFailed (false),
isRF64 (false)
{
using namespace WavFileHelpers;
if (metadataValues.size() > 0)
{
bwavChunk = BWAVChunk::createFrom (metadataValues);
@@ -465,6 +515,12 @@ public:
~WavAudioFormatWriter()
{
if ((bytesWritten & 1) != 0) // pad to an even length
{
++bytesWritten;
output->writeByte (0);
}
writeHeader();
}
@@ -488,8 +544,7 @@ public:
default: jassertfalse; break;
}
if (bytesWritten + bytes >= (uint32) 0xfff00000
|| ! output->write (tempBlock.getData(), bytes))
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
@@ -510,14 +565,27 @@ public:
private:
ScopedPointer<AudioData::Converter> converter;
MemoryBlock tempBlock, bwavChunk, smplChunk;
uint32 lengthInSamples, bytesWritten;
uint64 lengthInSamples, bytesWritten;
int64 headerPosition;
bool writeFailed;
bool writeFailed, isRF64;
static int getChannelMask (const int numChannels) throw()
{
switch (numChannels)
{
case 1: return 0;
case 2: return 1 + 2; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT
case 5: return 1 + 2 + 4 + 16 + 32; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT
case 6: return 1 + 2 + 4 + 8 + 16 + 32; // SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT
default: break;
}
static inline int chunkName (const char* const name) { return (int) ByteOrder::littleEndianInt (name); }
return 0;
}
void writeHeader()
{
using namespace WavFileHelpers;
const bool seekedOk = output->setPosition (headerPosition);
(void) seekedOk;
@@ -526,21 +594,62 @@ private:
jassert (seekedOk);
const int bytesPerFrame = numChannels * bitsPerSample / 8;
output->writeInt (chunkName ("RIFF"));
output->writeInt ((int) (lengthInSamples * bytesPerFrame
+ ((bwavChunk.getSize() > 0) ? (44 + bwavChunk.getSize()) : 36)
+ (smplChunk.getSize() > 0 ? smplChunk.getSize() + 8 : 0)));
int64 audioDataSize = bytesPerFrame * lengthInSamples;
int64 riffChunkSize = 4 /* 'WAVE' */ + 8 + 40 /* WAVEFORMATEX */
+ 8 + audioDataSize + (audioDataSize & 1)
+ (bwavChunk.getSize() > 0 ? (8 + bwavChunk.getSize()) : 0)
+ (smplChunk.getSize() > 0 ? (8 + smplChunk.getSize()) : 0)
+ (8 + 28); // (JUNK chunk)
riffChunkSize += (riffChunkSize & 0x1);
isRF64 = (riffChunkSize > 0xffffffff);
output->writeInt (chunkName (isRF64 ? "RF64" : "RIFF"));
output->writeInt (isRF64 ? -1 : (int) riffChunkSize);
output->writeInt (chunkName ("WAVE"));
if (! isRF64)
{
// write Junk chunk
output->writeInt (chunkName ("JUNK"));
output->writeInt (28);
output->writeRepeatedByte (0, 28);
}
else
{
// write ds64 chunk
output->writeInt (chunkName ("ds64"));
output->writeInt (28); // chunk size for uncompressed data (no table)
output->writeInt64 (riffChunkSize);
output->writeInt64 (audioDataSize);
output->writeRepeatedByte (0, 12);
}
output->writeInt (chunkName ("fmt "));
output->writeInt (16);
output->writeShort ((bitsPerSample < 32) ? (short) 1 /*WAVE_FORMAT_PCM*/
: (short) 3 /*WAVE_FORMAT_IEEE_FLOAT*/);
output->writeInt (40); // WAVEFORMATEX chunk size
output->writeShort ((short) (uint16) 0xfffe); // WAVE_FORMAT_EXTENSIBLE
output->writeShort ((short) numChannels);
output->writeInt ((int) sampleRate);
output->writeInt (bytesPerFrame * (int) sampleRate);
output->writeShort ((short) bytesPerFrame);
output->writeShort ((short) bitsPerSample);
output->writeInt ((int) (bytesPerFrame * sampleRate)); // nAvgBytesPerSec
output->writeShort ((short) bytesPerFrame); // nBlockAlign
output->writeShort ((short) bitsPerSample); // wBitsPerSample
output->writeShort (22); // cbSize (size of the extension)
output->writeShort ((short) bitsPerSample); // wValidBitsPerSample
output->writeInt (getChannelMask (numChannels));
const ExtensibleWavSubFormat pcmFormat
= { 0x00000001, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
const ExtensibleWavSubFormat IEEEFloatFormat
= { 0x00000003, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
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));
if (bwavChunk.getSize() > 0)
{
@@ -557,7 +666,7 @@ private:
}
output->writeInt (chunkName ("data"));
output->writeInt (lengthInSamples * bytesPerFrame);
output->writeInt (isRF64 ? -1 : (int) (lengthInSamples * bytesPerFrame));
usesFloatingPointData = (bitsPerSample == 32);
}
@@ -604,28 +713,19 @@ AudioFormatReader* WavAudioFormat::createReaderFor (InputStream* sourceStream,
return 0;
}
AudioFormatWriter* WavAudioFormat::createWriterFor (OutputStream* out,
double sampleRate,
unsigned int numChannels,
int bitsPerSample,
const StringPairArray& metadataValues,
int /*qualityOptionIndex*/)
AudioFormatWriter* WavAudioFormat::createWriterFor (OutputStream* out, double sampleRate,
unsigned int numChannels, int bitsPerSample,
const StringPairArray& metadataValues, int /*qualityOptionIndex*/)
{
if (getPossibleBitDepths().contains (bitsPerSample))
{
return new WavAudioFormatWriter (out,
sampleRate,
numChannels,
bitsPerSample,
metadataValues);
}
return new WavAudioFormatWriter (out, sampleRate, numChannels, bitsPerSample, metadataValues);
return 0;
}
namespace
namespace WavFileHelpers
{
bool juce_slowCopyOfWavFileWithNewMetadata (const File& file, const StringPairArray& metadata)
bool slowCopyWavFileWithNewMetadata (const File& file, const StringPairArray& metadata)
{
TemporaryFile tempFile (file);
@@ -661,7 +761,8 @@ namespace
bool WavAudioFormat::replaceMetadataInFile (const File& wavFile, const StringPairArray& newMetadata)
{
ScopedPointer <WavAudioFormatReader> reader ((WavAudioFormatReader*) createReaderFor (wavFile.createInputStream(), true));
using namespace WavFileHelpers;
ScopedPointer <WavAudioFormatReader> reader (static_cast <WavAudioFormatReader*> (createReaderFor (wavFile.createInputStream(), true)));
if (reader != 0)
{
@@ -692,7 +793,7 @@ bool WavAudioFormat::replaceMetadataInFile (const File& wavFile, const StringPai
}
}
return juce_slowCopyOfWavFileWithNewMetadata (wavFile, newMetadata);
return slowCopyWavFileWithNewMetadata (wavFile, newMetadata);
}


+ 7
- 7
src/audio/audio_sources/juce_AudioFormatReaderSource.cpp View File

@@ -50,7 +50,7 @@ AudioFormatReaderSource::~AudioFormatReaderSource()
delete reader;
}
void AudioFormatReaderSource::setNextReadPosition (int newPosition)
void AudioFormatReaderSource::setNextReadPosition (int64 newPosition)
{
nextPlayPos = newPosition;
}
@@ -60,15 +60,15 @@ void AudioFormatReaderSource::setLooping (bool shouldLoop)
looping = shouldLoop;
}
int AudioFormatReaderSource::getNextReadPosition() const
int64 AudioFormatReaderSource::getNextReadPosition() const
{
return (looping) ? (nextPlayPos % (int) reader->lengthInSamples)
: nextPlayPos;
return looping ? nextPlayPos % reader->lengthInSamples
: nextPlayPos;
}
int AudioFormatReaderSource::getTotalLength() const
int64 AudioFormatReaderSource::getTotalLength() const
{
return (int) reader->lengthInSamples;
return reader->lengthInSamples;
}
void AudioFormatReaderSource::prepareToPlay (int /*samplesPerBlockExpected*/,
@@ -84,7 +84,7 @@ void AudioFormatReaderSource::getNextAudioBlock (const AudioSourceChannelInfo& i
{
if (info.numSamples > 0)
{
const int start = nextPlayPos;
const int64 start = nextPlayPos;
if (looping)
{


+ 4
- 4
src/audio/audio_sources/juce_AudioFormatReaderSource.h View File

@@ -83,20 +83,20 @@ public:
//==============================================================================
/** Implements the PositionableAudioSource method. */
void setNextReadPosition (int newPosition);
void setNextReadPosition (int64 newPosition);
/** Implements the PositionableAudioSource method. */
int getNextReadPosition() const;
int64 getNextReadPosition() const;
/** Implements the PositionableAudioSource method. */
int getTotalLength() const;
int64 getTotalLength() const;
private:
//==============================================================================
AudioFormatReader* reader;
bool deleteReader;
int volatile nextPlayPos;
int64 volatile nextPlayPos;
bool volatile looping;
void readBufferSection (int start, int length, AudioSampleBuffer& buffer, int startSample);


+ 7
- 7
src/audio/audio_sources/juce_AudioTransportSource.cpp View File

@@ -159,7 +159,7 @@ void AudioTransportSource::stop()
void AudioTransportSource::setPosition (double newPosition)
{
if (sampleRate > 0.0)
setNextReadPosition (roundToInt (newPosition * sampleRate));
setNextReadPosition ((int64) (newPosition * sampleRate));
}
double AudioTransportSource::getCurrentPosition() const
@@ -175,30 +175,30 @@ double AudioTransportSource::getLengthInSeconds() const
return getTotalLength() / sampleRate;
}
void AudioTransportSource::setNextReadPosition (int newPosition)
void AudioTransportSource::setNextReadPosition (int64 newPosition)
{
if (positionableSource != 0)
{
if (sampleRate > 0 && sourceSampleRate > 0)
newPosition = roundToInt (newPosition * sourceSampleRate / sampleRate);
newPosition = (int64) (newPosition * sourceSampleRate / sampleRate);
positionableSource->setNextReadPosition (newPosition);
}
}
int AudioTransportSource::getNextReadPosition() const
int64 AudioTransportSource::getNextReadPosition() const
{
if (positionableSource != 0)
{
const double ratio = (sampleRate > 0 && sourceSampleRate > 0) ? sampleRate / sourceSampleRate : 1.0;
return roundToInt (positionableSource->getNextReadPosition() * ratio);
return (int64) (positionableSource->getNextReadPosition() * ratio);
}
return 0;
}
int AudioTransportSource::getTotalLength() const
int64 AudioTransportSource::getTotalLength() const
{
const ScopedLock sl (callbackLock);
@@ -206,7 +206,7 @@ int AudioTransportSource::getTotalLength() const
{
const double ratio = (sampleRate > 0 && sourceSampleRate > 0) ? sampleRate / sourceSampleRate : 1.0;
return roundToInt (positionableSource->getTotalLength() * ratio);
return (int64) (positionableSource->getTotalLength() * ratio);
}
return 0;


+ 3
- 3
src/audio/audio_sources/juce_AudioTransportSource.h View File

@@ -148,13 +148,13 @@ public:
//==============================================================================
/** Implements the PositionableAudioSource method. */
void setNextReadPosition (int newPosition);
void setNextReadPosition (int64 newPosition);
/** Implements the PositionableAudioSource method. */
int getNextReadPosition() const;
int64 getNextReadPosition() const;
/** Implements the PositionableAudioSource method. */
int getTotalLength() const;
int64 getTotalLength() const;
/** Implements the PositionableAudioSource method. */
bool isLooping() const;


+ 11
- 11
src/audio/audio_sources/juce_BufferingAudioSource.cpp View File

@@ -187,8 +187,8 @@ void BufferingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info
{
const ScopedLock sl (bufferStartPosLock);
const int validStart = jlimit (bufferValidStart, bufferValidEnd, nextPlayPos) - nextPlayPos;
const int validEnd = jlimit (bufferValidStart, bufferValidEnd, nextPlayPos + info.numSamples) - nextPlayPos;
const int validStart = (int) (jlimit (bufferValidStart, bufferValidEnd, nextPlayPos) - nextPlayPos);
const int validEnd = (int) (jlimit (bufferValidStart, bufferValidEnd, nextPlayPos + info.numSamples) - nextPlayPos);
if (validStart == validEnd)
{
@@ -247,14 +247,14 @@ void BufferingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info
thread->notify();
}
int BufferingAudioSource::getNextReadPosition() const
int64 BufferingAudioSource::getNextReadPosition() const
{
return (source->isLooping() && nextPlayPos > 0)
? nextPlayPos % source->getTotalLength()
: nextPlayPos;
}
void BufferingAudioSource::setNextReadPosition (int newPosition)
void BufferingAudioSource::setNextReadPosition (int64 newPosition)
{
const ScopedLock sl (bufferStartPosLock);
@@ -268,7 +268,7 @@ void BufferingAudioSource::setNextReadPosition (int newPosition)
bool BufferingAudioSource::readNextBufferChunk()
{
int newBVS, newBVE, sectionToReadStart, sectionToReadEnd;
int64 newBVS, newBVE, sectionToReadStart, sectionToReadEnd;
{
const ScopedLock sl (bufferStartPosLock);
@@ -280,7 +280,7 @@ bool BufferingAudioSource::readNextBufferChunk()
bufferValidEnd = 0;
}
newBVS = jmax (0, nextPlayPos);
newBVS = jmax ((int64) 0, nextPlayPos);
newBVE = newBVS + buffer.getNumSamples() - 4;
sectionToReadStart = 0;
sectionToReadEnd = 0;
@@ -297,8 +297,8 @@ bool BufferingAudioSource::readNextBufferChunk()
bufferValidStart = 0;
bufferValidEnd = 0;
}
else if (abs (newBVS - bufferValidStart) > 512
|| abs (newBVE - bufferValidEnd) > 512)
else if (std::abs ((int) (newBVS - bufferValidStart)) > 512
|| std::abs ((int) (newBVE - bufferValidEnd)) > 512)
{
newBVE = jmin (newBVE, bufferValidEnd + maxChunkSize);
@@ -318,7 +318,7 @@ bool BufferingAudioSource::readNextBufferChunk()
if (bufferIndexStart < bufferIndexEnd)
{
readBufferSection (sectionToReadStart,
sectionToReadEnd - sectionToReadStart,
(int) (sectionToReadEnd - sectionToReadStart),
bufferIndexStart);
}
else
@@ -330,7 +330,7 @@ bool BufferingAudioSource::readNextBufferChunk()
bufferIndexStart);
readBufferSection (sectionToReadStart + initialSize,
(sectionToReadEnd - sectionToReadStart) - initialSize,
(int) (sectionToReadEnd - sectionToReadStart) - initialSize,
0);
}
@@ -347,7 +347,7 @@ bool BufferingAudioSource::readNextBufferChunk()
}
}
void BufferingAudioSource::readBufferSection (int start, int length, int bufferOffset)
void BufferingAudioSource::readBufferSection (const int64 start, const int length, const int bufferOffset)
{
if (source->getNextReadPosition() != start)
source->setNextReadPosition (start);


+ 5
- 5
src/audio/audio_sources/juce_BufferingAudioSource.h View File

@@ -75,13 +75,13 @@ public:
//==============================================================================
/** Implements the PositionableAudioSource method. */
void setNextReadPosition (int newPosition);
void setNextReadPosition (int64 newPosition);
/** Implements the PositionableAudioSource method. */
int getNextReadPosition() const;
int64 getNextReadPosition() const;
/** Implements the PositionableAudioSource method. */
int getTotalLength() const { return source->getTotalLength(); }
int64 getTotalLength() const { return source->getTotalLength(); }
/** Implements the PositionableAudioSource method. */
bool isLooping() const { return source->isLooping(); }
@@ -93,13 +93,13 @@ private:
int numberOfSamplesToBuffer;
AudioSampleBuffer buffer;
CriticalSection bufferStartPosLock;
int volatile bufferValidStart, bufferValidEnd, nextPlayPos;
int64 volatile bufferValidStart, bufferValidEnd, nextPlayPos;
bool wasSourceLooping;
double volatile sampleRate;
friend class SharedBufferingAudioSourceThread;
bool readNextBufferChunk();
void readBufferSection (int start, int length, int bufferOffset);
void readBufferSection (int64 start, int length, int bufferOffset);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BufferingAudioSource);
};


+ 3
- 3
src/audio/audio_sources/juce_PositionableAudioSource.h View File

@@ -59,16 +59,16 @@ public:
Note that this may be called on a different thread to getNextAudioBlock(),
so the subclass should make sure it's synchronised.
*/
virtual void setNextReadPosition (int newPosition) = 0;
virtual void setNextReadPosition (int64 newPosition) = 0;
/** Returns the position from which the next block will be returned.
@see setNextReadPosition
*/
virtual int getNextReadPosition() const = 0;
virtual int64 getNextReadPosition() const = 0;
/** Returns the total length of the stream (in samples). */
virtual int getTotalLength() const = 0;
virtual int64 getTotalLength() const = 0;
/** Returns true if this source is actually playing in a loop. */
virtual bool isLooping() const = 0;


+ 1
- 1
src/audio/dsp/juce_AudioSampleBuffer.cpp View File

@@ -547,7 +547,7 @@ float AudioSampleBuffer::getRMSLevel (const int channel,
void AudioSampleBuffer::readFromAudioReader (AudioFormatReader* reader,
const int startSample,
const int numSamples,
const int readerStartSample,
const int64 readerStartSample,
const bool useLeftChan,
const bool useRightChan)
{


+ 1
- 1
src/audio/dsp/juce_AudioSampleBuffer.h View File

@@ -405,7 +405,7 @@ public:
void readFromAudioReader (AudioFormatReader* reader,
int startSample,
int numSamples,
int readerStartSample,
int64 readerStartSample,
bool useReaderLeftChan,
bool useReaderRightChan);


+ 6
- 0
src/io/streams/juce_OutputStream.cpp View File

@@ -78,6 +78,12 @@ void OutputStream::writeByte (char byte)
write (&byte, 1);
}
void OutputStream::writeRepeatedByte (uint8 byte, int numTimesToRepeat)
{
while (--numTimesToRepeat >= 0)
writeByte (byte);
}
void OutputStream::writeShort (short value)
{
const unsigned short v = ByteOrder::swapIfBigEndian ((unsigned short) value);


+ 3
- 0
src/io/streams/juce_OutputStream.h View File

@@ -155,6 +155,9 @@ public:
*/
virtual void writeDoubleBigEndian (double value);
/** Writes a byte to the output stream a given number of times. */
virtual void writeRepeatedByte (uint8 byte, int numTimesToRepeat);
/** Writes a condensed binary encoding of a 32-bit integer.
If you're storing a lot of integers which are unlikely to have very large values,


Loading…
Cancel
Save