Made audio stream handling safe for long streams
This commit is contained in:
parent
d1bbe8538e
commit
522f6c2019
|
@ -9,10 +9,10 @@ public:
|
||||||
virtual ~AudioStream() {}
|
virtual ~AudioStream() {}
|
||||||
virtual std::unique_ptr<AudioStream> clone(bool reset) const = 0;
|
virtual std::unique_ptr<AudioStream> clone(bool reset) const = 0;
|
||||||
virtual int getSampleRate() const = 0;
|
virtual int getSampleRate() const = 0;
|
||||||
virtual int getSampleCount() const = 0;
|
virtual int64_t getSampleCount() const = 0;
|
||||||
TimeRange getTruncatedRange() const;
|
TimeRange getTruncatedRange() const;
|
||||||
virtual int getSampleIndex() const = 0;
|
virtual int64_t getSampleIndex() const = 0;
|
||||||
virtual void seek(int sampleIndex) = 0;
|
virtual void seek(int64_t sampleIndex) = 0;
|
||||||
bool endOfStream() const;
|
bool endOfStream() const;
|
||||||
virtual float readSample() = 0;
|
virtual float readSample() = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -29,15 +29,15 @@ int AudioStreamSegment::getSampleRate() const {
|
||||||
return audioStream->getSampleRate();
|
return audioStream->getSampleRate();
|
||||||
}
|
}
|
||||||
|
|
||||||
int AudioStreamSegment::getSampleCount() const {
|
int64_t AudioStreamSegment::getSampleCount() const {
|
||||||
return sampleCount;
|
return sampleCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AudioStreamSegment::getSampleIndex() const {
|
int64_t AudioStreamSegment::getSampleIndex() const {
|
||||||
return audioStream->getSampleIndex() - sampleOffset;
|
return audioStream->getSampleIndex() - sampleOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioStreamSegment::seek(int sampleIndex) {
|
void AudioStreamSegment::seek(int64_t sampleIndex) {
|
||||||
audioStream->seek(sampleIndex + sampleOffset);
|
audioStream->seek(sampleIndex + sampleOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,14 +8,14 @@ public:
|
||||||
AudioStreamSegment(const AudioStreamSegment& rhs, bool reset);
|
AudioStreamSegment(const AudioStreamSegment& rhs, bool reset);
|
||||||
std::unique_ptr<AudioStream> clone(bool reset) const override;
|
std::unique_ptr<AudioStream> clone(bool reset) const override;
|
||||||
int getSampleRate() const override;
|
int getSampleRate() const override;
|
||||||
int getSampleCount() const override;
|
int64_t getSampleCount() const override;
|
||||||
int getSampleIndex() const override;
|
int64_t getSampleIndex() const override;
|
||||||
void seek(int sampleIndex) override;
|
void seek(int64_t sampleIndex) override;
|
||||||
float readSample() override;
|
float readSample() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<AudioStream> audioStream;
|
std::unique_ptr<AudioStream> audioStream;
|
||||||
int sampleOffset, sampleCount;
|
int64_t sampleOffset, sampleCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<AudioStream> createSegment(std::unique_ptr<AudioStream> audioStream, const TimeRange& range);
|
std::unique_ptr<AudioStream> createSegment(std::unique_ptr<AudioStream> audioStream, const TimeRange& range);
|
||||||
|
|
|
@ -22,15 +22,15 @@ int DCOffset::getSampleRate() const {
|
||||||
return inputStream->getSampleRate();
|
return inputStream->getSampleRate();
|
||||||
}
|
}
|
||||||
|
|
||||||
int DCOffset::getSampleCount() const {
|
int64_t DCOffset::getSampleCount() const {
|
||||||
return inputStream->getSampleCount();
|
return inputStream->getSampleCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
int DCOffset::getSampleIndex() const {
|
int64_t DCOffset::getSampleIndex() const {
|
||||||
return inputStream->getSampleIndex();
|
return inputStream->getSampleIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DCOffset::seek(int sampleIndex) {
|
void DCOffset::seek(int64_t sampleIndex) {
|
||||||
inputStream->seek(sampleIndex);
|
inputStream->seek(sampleIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,11 +53,11 @@ float getDCOffset(AudioStream& audioStream) {
|
||||||
fadingMeanSampleCount = 1 * sampleRate;
|
fadingMeanSampleCount = 1 * sampleRate;
|
||||||
} else {
|
} else {
|
||||||
// Short audio file. Average over the entire length.
|
// Short audio file. Average over the entire length.
|
||||||
flatMeanSampleCount = audioStream.getSampleCount();
|
flatMeanSampleCount = static_cast<int>(audioStream.getSampleCount());
|
||||||
fadingMeanSampleCount = 0;
|
fadingMeanSampleCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int originalSampleIndex = audioStream.getSampleIndex();
|
int64_t originalSampleIndex = audioStream.getSampleIndex();
|
||||||
audioStream.seek(0);
|
audioStream.seek(0);
|
||||||
auto restorePosition = gsl::finally([&]() { audioStream.seek(originalSampleIndex); });
|
auto restorePosition = gsl::finally([&]() { audioStream.seek(originalSampleIndex); });
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,9 @@ public:
|
||||||
DCOffset(const DCOffset& rhs, bool reset);
|
DCOffset(const DCOffset& rhs, bool reset);
|
||||||
std::unique_ptr<AudioStream> clone(bool reset) const override;
|
std::unique_ptr<AudioStream> clone(bool reset) const override;
|
||||||
int getSampleRate() const override;
|
int getSampleRate() const override;
|
||||||
int getSampleCount() const override;
|
int64_t getSampleCount() const override;
|
||||||
int getSampleIndex() const override;
|
int64_t getSampleIndex() const override;
|
||||||
void seek(int sampleIndex) override;
|
void seek(int64_t sampleIndex) override;
|
||||||
float readSample() override;
|
float readSample() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -37,15 +37,15 @@ int SampleRateConverter::getSampleRate() const {
|
||||||
return outputSampleRate;
|
return outputSampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SampleRateConverter::getSampleCount() const {
|
int64_t SampleRateConverter::getSampleCount() const {
|
||||||
return outputSampleCount;
|
return outputSampleCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SampleRateConverter::getSampleIndex() const {
|
int64_t SampleRateConverter::getSampleIndex() const {
|
||||||
return nextOutputSampleIndex;
|
return nextOutputSampleIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SampleRateConverter::seek(int sampleIndex) {
|
void SampleRateConverter::seek(int64_t sampleIndex) {
|
||||||
if (sampleIndex < 0 || sampleIndex >= outputSampleCount) throw std::invalid_argument("sampleIndex out of range.");
|
if (sampleIndex < 0 || sampleIndex >= outputSampleCount) throw std::invalid_argument("sampleIndex out of range.");
|
||||||
|
|
||||||
nextOutputSampleIndex = sampleIndex;
|
nextOutputSampleIndex = sampleIndex;
|
||||||
|
@ -66,12 +66,12 @@ float SampleRateConverter::mean(double inputStart, double inputEnd) {
|
||||||
double sum = 0;
|
double sum = 0;
|
||||||
|
|
||||||
// ... first sample (weight <= 1)
|
// ... first sample (weight <= 1)
|
||||||
int startIndex = static_cast<int>(inputStart);
|
int64_t startIndex = static_cast<int64_t>(inputStart);
|
||||||
sum += getInputSample(startIndex) * ((startIndex + 1) - inputStart);
|
sum += getInputSample(startIndex) * ((startIndex + 1) - inputStart);
|
||||||
|
|
||||||
// ... middle samples (weight 1 each)
|
// ... middle samples (weight 1 each)
|
||||||
int endIndex = static_cast<int>(inputEnd);
|
int64_t endIndex = static_cast<int64_t>(inputEnd);
|
||||||
for (int index = startIndex + 1; index < endIndex; index++) {
|
for (int64_t index = startIndex + 1; index < endIndex; ++index) {
|
||||||
sum += getInputSample(index);
|
sum += getInputSample(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ float SampleRateConverter::mean(double inputStart, double inputEnd) {
|
||||||
return static_cast<float>(sum / (inputEnd - inputStart));
|
return static_cast<float>(sum / (inputEnd - inputStart));
|
||||||
}
|
}
|
||||||
|
|
||||||
float SampleRateConverter::getInputSample(int sampleIndex) {
|
float SampleRateConverter::getInputSample(int64_t sampleIndex) {
|
||||||
sampleIndex = std::min(sampleIndex, inputStream->getSampleCount() - 1);
|
sampleIndex = std::min(sampleIndex, inputStream->getSampleCount() - 1);
|
||||||
if (sampleIndex < 0) return 0.0f;
|
if (sampleIndex < 0) return 0.0f;
|
||||||
|
|
||||||
|
|
|
@ -9,24 +9,24 @@ public:
|
||||||
SampleRateConverter(const SampleRateConverter& rhs, bool reset);
|
SampleRateConverter(const SampleRateConverter& rhs, bool reset);
|
||||||
std::unique_ptr<AudioStream> clone(bool reset) const override;
|
std::unique_ptr<AudioStream> clone(bool reset) const override;
|
||||||
int getSampleRate() const override;
|
int getSampleRate() const override;
|
||||||
int getSampleCount() const override;
|
int64_t getSampleCount() const override;
|
||||||
int getSampleIndex() const override;
|
int64_t getSampleIndex() const override;
|
||||||
void seek(int sampleIndex) override;
|
void seek(int64_t sampleIndex) override;
|
||||||
float readSample() override;
|
float readSample() override;
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<AudioStream> inputStream;
|
std::unique_ptr<AudioStream> inputStream;
|
||||||
double downscalingFactor; // input sample rate / output sample rate
|
double downscalingFactor; // input sample rate / output sample rate
|
||||||
|
|
||||||
int outputSampleRate;
|
int outputSampleRate;
|
||||||
int outputSampleCount;
|
int64_t outputSampleCount;
|
||||||
|
|
||||||
float lastInputSample;
|
float lastInputSample;
|
||||||
int lastInputSampleIndex;
|
int64_t lastInputSampleIndex;
|
||||||
|
|
||||||
int nextOutputSampleIndex;
|
int64_t nextOutputSampleIndex;
|
||||||
|
|
||||||
float mean(double start, double end);
|
float mean(double start, double end);
|
||||||
float getInputSample(int sampleIndex);
|
float getInputSample(int64_t sampleIndex);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<AudioStream> convertSampleRate(std::unique_ptr<AudioStream> audioStream, int sampleRate);
|
std::unique_ptr<AudioStream> convertSampleRate(std::unique_ptr<AudioStream> audioStream, int sampleRate);
|
|
@ -24,15 +24,15 @@ int UnboundedStream::getSampleRate() const {
|
||||||
return innerStream->getSampleRate();
|
return innerStream->getSampleRate();
|
||||||
}
|
}
|
||||||
|
|
||||||
int UnboundedStream::getSampleCount() const {
|
int64_t UnboundedStream::getSampleCount() const {
|
||||||
return innerStream->getSampleCount();
|
return innerStream->getSampleCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
int UnboundedStream::getSampleIndex() const {
|
int64_t UnboundedStream::getSampleIndex() const {
|
||||||
return sampleIndex;
|
return sampleIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnboundedStream::seek(int sampleIndex) {
|
void UnboundedStream::seek(int64_t sampleIndex) {
|
||||||
this->sampleIndex = sampleIndex;
|
this->sampleIndex = sampleIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,13 +10,13 @@ public:
|
||||||
UnboundedStream(const UnboundedStream& rhs, bool reset);
|
UnboundedStream(const UnboundedStream& rhs, bool reset);
|
||||||
std::unique_ptr<AudioStream> clone(bool reset) const override;
|
std::unique_ptr<AudioStream> clone(bool reset) const override;
|
||||||
int getSampleRate() const override;
|
int getSampleRate() const override;
|
||||||
int getSampleCount() const override;
|
int64_t getSampleCount() const override;
|
||||||
int getSampleIndex() const override;
|
int64_t getSampleIndex() const override;
|
||||||
void seek(int sampleIndex) override;
|
void seek(int64_t sampleIndex) override;
|
||||||
float readSample() override;
|
float readSample() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<AudioStream> innerStream;
|
std::unique_ptr<AudioStream> innerStream;
|
||||||
int sampleIndex;
|
int64_t sampleIndex;
|
||||||
boost::optional<float> firstSample, lastSample;
|
boost::optional<float> firstSample, lastSample;
|
||||||
};
|
};
|
||||||
|
|
|
@ -173,15 +173,15 @@ int WaveFileReader::getSampleRate() const {
|
||||||
return frameRate;
|
return frameRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
int WaveFileReader::getSampleCount() const {
|
int64_t WaveFileReader::getSampleCount() const {
|
||||||
return frameCount;
|
return frameCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
int WaveFileReader::getSampleIndex() const {
|
int64_t WaveFileReader::getSampleIndex() const {
|
||||||
return sampleIndex;
|
return sampleIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaveFileReader::seek(int sampleIndex) {
|
void WaveFileReader::seek(int64_t sampleIndex) {
|
||||||
if (sampleIndex < 0 || sampleIndex > sampleCount) throw std::invalid_argument("sampleIndex out of range.");
|
if (sampleIndex < 0 || sampleIndex > sampleCount) throw std::invalid_argument("sampleIndex out of range.");
|
||||||
|
|
||||||
file.seekg(dataOffset + static_cast<std::streamoff>(sampleIndex * channelCount * bytesPerSample));
|
file.seekg(dataOffset + static_cast<std::streamoff>(sampleIndex * channelCount * bytesPerSample));
|
||||||
|
|
|
@ -17,9 +17,9 @@ public:
|
||||||
WaveFileReader(const WaveFileReader& rhs, bool reset);
|
WaveFileReader(const WaveFileReader& rhs, bool reset);
|
||||||
std::unique_ptr<AudioStream> clone(bool reset) const override;
|
std::unique_ptr<AudioStream> clone(bool reset) const override;
|
||||||
int getSampleRate() const override ;
|
int getSampleRate() const override ;
|
||||||
int getSampleCount() const override;
|
int64_t getSampleCount() const override;
|
||||||
int getSampleIndex() const override;
|
int64_t getSampleIndex() const override;
|
||||||
void seek(int sampleIndex) override;
|
void seek(int64_t sampleIndex) override;
|
||||||
float readSample() override;
|
float readSample() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -31,9 +31,9 @@ private:
|
||||||
int bytesPerSample;
|
int bytesPerSample;
|
||||||
SampleFormat sampleFormat;
|
SampleFormat sampleFormat;
|
||||||
int frameRate;
|
int frameRate;
|
||||||
int frameCount;
|
int64_t frameCount;
|
||||||
int channelCount;
|
int channelCount;
|
||||||
int sampleCount;
|
int64_t sampleCount;
|
||||||
std::streampos dataOffset;
|
std::streampos dataOffset;
|
||||||
int sampleIndex;
|
int64_t sampleIndex;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue